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  

11  

12  
#include <boost/url/detail/config.hpp>
12  
#include <boost/url/detail/config.hpp>
13  
#include <boost/url/url_base.hpp>
13  
#include <boost/url/url_base.hpp>
14  
#include <boost/url/encode.hpp>
14  
#include <boost/url/encode.hpp>
15  
#include <boost/url/error.hpp>
15  
#include <boost/url/error.hpp>
16  
#include <boost/url/host_type.hpp>
16  
#include <boost/url/host_type.hpp>
17  
#include <boost/url/scheme.hpp>
17  
#include <boost/url/scheme.hpp>
18  
#include <boost/url/url_view.hpp>
18  
#include <boost/url/url_view.hpp>
19  
#include <boost/url/detail/any_params_iter.hpp>
19  
#include <boost/url/detail/any_params_iter.hpp>
20  
#include <boost/url/detail/any_segments_iter.hpp>
20  
#include <boost/url/detail/any_segments_iter.hpp>
21  
#include <boost/url/detail/decode.hpp>
21  
#include <boost/url/detail/decode.hpp>
22  
#include <boost/url/detail/encode.hpp>
22  
#include <boost/url/detail/encode.hpp>
23  
#include <boost/url/detail/except.hpp>
23  
#include <boost/url/detail/except.hpp>
24  
#include "detail/normalize.hpp"
24  
#include "detail/normalize.hpp"
25  
#include "detail/path.hpp"
25  
#include "detail/path.hpp"
26  
#include "detail/print.hpp"
26  
#include "detail/print.hpp"
27  
#include <boost/url/grammar/ci_string.hpp>
27  
#include <boost/url/grammar/ci_string.hpp>
28  
#include <boost/url/rfc/authority_rule.hpp>
28  
#include <boost/url/rfc/authority_rule.hpp>
29  
#include <boost/url/rfc/query_rule.hpp>
29  
#include <boost/url/rfc/query_rule.hpp>
30  
#include <boost/url/rfc/ipv6_address_rule.hpp>
30  
#include <boost/url/rfc/ipv6_address_rule.hpp>
31  
#include "rfc/detail/charsets.hpp"
31  
#include "rfc/detail/charsets.hpp"
32  
#include "rfc/detail/host_rule.hpp"
32  
#include "rfc/detail/host_rule.hpp"
33  
#include "rfc/detail/ipvfuture_rule.hpp"
33  
#include "rfc/detail/ipvfuture_rule.hpp"
34  
#include "boost/url/rfc/detail/path_rules.hpp"
34  
#include "boost/url/rfc/detail/path_rules.hpp"
35  
#include "rfc/detail/port_rule.hpp"
35  
#include "rfc/detail/port_rule.hpp"
36  
#include "rfc/detail/scheme_rule.hpp"
36  
#include "rfc/detail/scheme_rule.hpp"
37  
#include "rfc/detail/userinfo_rule.hpp"
37  
#include "rfc/detail/userinfo_rule.hpp"
38  
#include <boost/url/grammar/parse.hpp>
38  
#include <boost/url/grammar/parse.hpp>
39  
#include "detail/move_chars.hpp"
39  
#include "detail/move_chars.hpp"
40  
#include <cstring>
40  
#include <cstring>
41  
#include <iostream>
41  
#include <iostream>
42  
#include <stdexcept>
42  
#include <stdexcept>
43  
#include <utility>
43  
#include <utility>
44  

44  

45  
namespace boost {
45  
namespace boost {
46  
namespace urls {
46  
namespace urls {
47  

47  

48  
//------------------------------------------------
48  
//------------------------------------------------
49  

49  

50  
// these objects help handle the cases
50  
// these objects help handle the cases
51  
// where the user passes in strings that
51  
// where the user passes in strings that
52  
// come from inside the url buffer.
52  
// come from inside the url buffer.
53  

53  

54  
url_base::
54  
url_base::
55  
op_t::
55  
op_t::
56  
~op_t()
56  
~op_t()
57  
{
57  
{
58  
    if(old)
58  
    if(old)
59  
        u.cleanup(*this);
59  
        u.cleanup(*this);
60  
    u.check_invariants();
60  
    u.check_invariants();
61  
}
61  
}
62  

62  

63  
url_base::
63  
url_base::
64  
op_t::
64  
op_t::
65  
op_t(
65  
op_t(
66  
    url_base& impl_,
66  
    url_base& impl_,
67  
    core::string_view* s0_,
67  
    core::string_view* s0_,
68  
    core::string_view* s1_) noexcept
68  
    core::string_view* s1_) noexcept
69  
    : u(impl_)
69  
    : u(impl_)
70  
    , s0(s0_)
70  
    , s0(s0_)
71  
    , s1(s1_)
71  
    , s1(s1_)
72  
{
72  
{
73  
    u.check_invariants();
73  
    u.check_invariants();
74  
}
74  
}
75  

75  

76  
void
76  
void
77  
url_base::
77  
url_base::
78  
op_t::
78  
op_t::
79  
move(
79  
move(
80  
    char* dest,
80  
    char* dest,
81  
    char const* src,
81  
    char const* src,
82  
    std::size_t n) noexcept
82  
    std::size_t n) noexcept
83  
{
83  
{
84  
    if(! n)
84  
    if(! n)
85  
        return;
85  
        return;
86  
    if(s0)
86  
    if(s0)
87  
    {
87  
    {
88  
        if(s1)
88  
        if(s1)
89  
            return detail::move_chars(
89  
            return detail::move_chars(
90  
             dest, src, n, *s0, *s1);
90  
             dest, src, n, *s0, *s1);
91  
        return detail::move_chars(
91  
        return detail::move_chars(
92  
            dest, src, n, *s0);
92  
            dest, src, n, *s0);
93  
    }
93  
    }
94  
    detail::move_chars(
94  
    detail::move_chars(
95  
        dest, src, n);
95  
        dest, src, n);
96  
}
96  
}
97  

97  

98  
//------------------------------------------------
98  
//------------------------------------------------
99  

99  

100  
// construct reference
100  
// construct reference
101  
url_base::
101  
url_base::
102  
url_base(
102  
url_base(
103  
    detail::url_impl const& impl) noexcept
103  
    detail::url_impl const& impl) noexcept
104  
    : url_view_base(impl)
104  
    : url_view_base(impl)
105  
{
105  
{
106  
}
106  
}
107  

107  

108  
void
108  
void
109  
url_base::
109  
url_base::
110  
reserve_impl(std::size_t n)
110  
reserve_impl(std::size_t n)
111  
{
111  
{
112  
    op_t op(*this);
112  
    op_t op(*this);
113  
    reserve_impl(n, op);
113  
    reserve_impl(n, op);
114  
    if(s_)
114  
    if(s_)
115  
        s_[size()] = '\0';
115  
        s_[size()] = '\0';
116  
}
116  
}
117  

117  

118  
// make a copy of u
118  
// make a copy of u
119  
void
119  
void
120  
url_base::
120  
url_base::
121  
copy(url_view_base const& u)
121  
copy(url_view_base const& u)
122  
{
122  
{
123  
    if (this == &u)
123  
    if (this == &u)
124  
        return;
124  
        return;
125  
    op_t op(*this);
125  
    op_t op(*this);
126  
    if(u.size() == 0)
126  
    if(u.size() == 0)
127  
    {
127  
    {
128  
        clear();
128  
        clear();
129  
        return;
129  
        return;
130  
    }
130  
    }
131  
    reserve_impl(
131  
    reserve_impl(
132  
        u.size(), op);
132  
        u.size(), op);
133  
    impl_ = *u.pi_;
133  
    impl_ = *u.pi_;
134  
    impl_.cs_ = s_;
134  
    impl_.cs_ = s_;
135  
    impl_.from_ = {from::url};
135  
    impl_.from_ = {from::url};
136  
    std::memcpy(s_,
136  
    std::memcpy(s_,
137  
        u.data(), u.size());
137  
        u.data(), u.size());
138  
    s_[size()] = '\0';
138  
    s_[size()] = '\0';
139  
}
139  
}
140  

140  

141  
//------------------------------------------------
141  
//------------------------------------------------
142  
//
142  
//
143  
// Scheme
143  
// Scheme
144  
//
144  
//
145  
//------------------------------------------------
145  
//------------------------------------------------
146  

146  

147  
url_base&
147  
url_base&
148  
url_base::
148  
url_base::
149  
set_scheme(core::string_view s)
149  
set_scheme(core::string_view s)
150  
{
150  
{
151  
    set_scheme_impl(
151  
    set_scheme_impl(
152  
        s, string_to_scheme(s));
152  
        s, string_to_scheme(s));
153  
    return *this;
153  
    return *this;
154  
}
154  
}
155  

155  

156  
url_base&
156  
url_base&
157  
url_base::
157  
url_base::
158  
set_scheme_id(urls::scheme id)
158  
set_scheme_id(urls::scheme id)
159  
{
159  
{
160  
    if(id == urls::scheme::unknown)
160  
    if(id == urls::scheme::unknown)
161  
        detail::throw_invalid_argument();
161  
        detail::throw_invalid_argument();
162  
    if(id == urls::scheme::none)
162  
    if(id == urls::scheme::none)
163  
        return remove_scheme();
163  
        return remove_scheme();
164  
    set_scheme_impl(to_string(id), id);
164  
    set_scheme_impl(to_string(id), id);
165  
    return *this;
165  
    return *this;
166  
}
166  
}
167  

167  

168  
url_base&
168  
url_base&
169  
url_base::
169  
url_base::
170  
remove_scheme()
170  
remove_scheme()
171  
{
171  
{
172  
    op_t op(*this);
172  
    op_t op(*this);
173  
    auto const sn = impl_.len(id_scheme);
173  
    auto const sn = impl_.len(id_scheme);
174  
    if(sn == 0)
174  
    if(sn == 0)
175  
        return *this;
175  
        return *this;
176  
    auto const po = impl_.offset(id_path);
176  
    auto const po = impl_.offset(id_path);
177  
    auto fseg = first_segment();
177  
    auto fseg = first_segment();
178  
    bool const encode_colon =
178  
    bool const encode_colon =
179  
        !has_authority() &&
179  
        !has_authority() &&
180  
        impl_.nseg_ > 0 &&
180  
        impl_.nseg_ > 0 &&
181  
        s_[po] != '/' &&
181  
        s_[po] != '/' &&
182  
        fseg.contains(':');
182  
        fseg.contains(':');
183  
    if(!encode_colon)
183  
    if(!encode_colon)
184  
    {
184  
    {
185  
        // just remove the scheme
185  
        // just remove the scheme
186  
        resize_impl(id_scheme, 0, op);
186  
        resize_impl(id_scheme, 0, op);
187  
        impl_.scheme_ = urls::scheme::none;
187  
        impl_.scheme_ = urls::scheme::none;
188  
        check_invariants();
188  
        check_invariants();
189  
        return *this;
189  
        return *this;
190  
    }
190  
    }
191  
    // encode any ":" in the first path segment
191  
    // encode any ":" in the first path segment
192  
    BOOST_ASSERT(sn >= 2);
192  
    BOOST_ASSERT(sn >= 2);
193  
    auto pn = impl_.len(id_path);
193  
    auto pn = impl_.len(id_path);
194  
    std::size_t cn = 0;
194  
    std::size_t cn = 0;
195  
    for (char c: fseg)
195  
    for (char c: fseg)
196  
        cn += c == ':';
196  
        cn += c == ':';
197  
    std::size_t new_size =
197  
    std::size_t new_size =
198  
        size() - sn + 2 * cn;
198  
        size() - sn + 2 * cn;
199  
    bool need_resize = new_size > size();
199  
    bool need_resize = new_size > size();
200  
    if (need_resize)
200  
    if (need_resize)
201  
    {
201  
    {
202  
        resize_impl(
202  
        resize_impl(
203  
            id_path, pn + 2 * cn, op);
203  
            id_path, pn + 2 * cn, op);
204  
    }
204  
    }
205  
    // move [id_scheme, id_path) left
205  
    // move [id_scheme, id_path) left
206  
    op.move(
206  
    op.move(
207  
        s_,
207  
        s_,
208  
        s_ + sn,
208  
        s_ + sn,
209  
        po - sn);
209  
        po - sn);
210  
    // move [id_path, id_query) left
210  
    // move [id_path, id_query) left
211  
    auto qo = impl_.offset(id_query);
211  
    auto qo = impl_.offset(id_query);
212  
    op.move(
212  
    op.move(
213  
        s_ + po - sn,
213  
        s_ + po - sn,
214  
        s_ + po,
214  
        s_ + po,
215  
        qo - po);
215  
        qo - po);
216  
    // move [id_query, id_end) left
216  
    // move [id_query, id_end) left
217  
    op.move(
217  
    op.move(
218  
        s_ + qo - sn + 2 * cn,
218  
        s_ + qo - sn + 2 * cn,
219  
        s_ + qo,
219  
        s_ + qo,
220  
        impl_.offset(id_end) - qo);
220  
        impl_.offset(id_end) - qo);
221  

221  

222  
    // adjust part offsets.
222  
    // adjust part offsets.
223  
    // (po and qo are invalidated)
223  
    // (po and qo are invalidated)
224  
    if (need_resize)
224  
    if (need_resize)
225  
    {
225  
    {
226  
        impl_.adjust_left(id_user, id_end, sn);
226  
        impl_.adjust_left(id_user, id_end, sn);
227  
    }
227  
    }
228  
    else
228  
    else
229  
    {
229  
    {
230  
        impl_.adjust_left(id_user, id_path, sn);
230  
        impl_.adjust_left(id_user, id_path, sn);
231  
        impl_.adjust_left(id_query, id_end, sn - 2 * cn);
231  
        impl_.adjust_left(id_query, id_end, sn - 2 * cn);
232  
    }
232  
    }
233  
    if (encode_colon)
233  
    if (encode_colon)
234  
    {
234  
    {
235  
        // move the 2nd, 3rd, ... segments
235  
        // move the 2nd, 3rd, ... segments
236  
        auto begin = s_ + impl_.offset(id_path);
236  
        auto begin = s_ + impl_.offset(id_path);
237  
        auto it = begin;
237  
        auto it = begin;
238  
        auto end = begin + pn;
238  
        auto end = begin + pn;
239  
        while (*it != '/' &&
239  
        while (*it != '/' &&
240  
               it != end)
240  
               it != end)
241  
            ++it;
241  
            ++it;
242  
        // we don't need op here because this is
242  
        // we don't need op here because this is
243  
        // an internal operation
243  
        // an internal operation
244  
        std::memmove(it + (2 * cn), it, end - it);
244  
        std::memmove(it + (2 * cn), it, end - it);
245  

245  

246  
        // move 1st segment
246  
        // move 1st segment
247  
        auto src = s_ + impl_.offset(id_path) + pn;
247  
        auto src = s_ + impl_.offset(id_path) + pn;
248  
        auto dest = s_ + impl_.offset(id_query);
248  
        auto dest = s_ + impl_.offset(id_query);
249  
        src -= end - it;
249  
        src -= end - it;
250  
        dest -= end - it;
250  
        dest -= end - it;
251  
        pn -= end - it;
251  
        pn -= end - it;
252  
        do {
252  
        do {
253  
            --src;
253  
            --src;
254  
            --dest;
254  
            --dest;
255  
            if (*src != ':')
255  
            if (*src != ':')
256  
            {
256  
            {
257  
                *dest = *src;
257  
                *dest = *src;
258  
            }
258  
            }
259  
            else
259  
            else
260  
            {
260  
            {
261  
                // use uppercase as required by
261  
                // use uppercase as required by
262  
                // syntax-based normalization
262  
                // syntax-based normalization
263  
                *dest-- = 'A';
263  
                *dest-- = 'A';
264  
                *dest-- = '3';
264  
                *dest-- = '3';
265  
                *dest = '%';
265  
                *dest = '%';
266  
            }
266  
            }
267  
            --pn;
267  
            --pn;
268  
        } while (pn);
268  
        } while (pn);
269  
    }
269  
    }
270  
    s_[size()] = '\0';
270  
    s_[size()] = '\0';
271  
    impl_.scheme_ = urls::scheme::none;
271  
    impl_.scheme_ = urls::scheme::none;
272  
    return *this;
272  
    return *this;
273  
}
273  
}
274  

274  

275  
//------------------------------------------------
275  
//------------------------------------------------
276  
//
276  
//
277  
// Authority
277  
// Authority
278  
//
278  
//
279  
//------------------------------------------------
279  
//------------------------------------------------
280  

280  

281  
url_base&
281  
url_base&
282  
url_base::
282  
url_base::
283  
set_encoded_authority(
283  
set_encoded_authority(
284  
    pct_string_view s)
284  
    pct_string_view s)
285  
{
285  
{
286  
    op_t op(*this, &detail::ref(s));
286  
    op_t op(*this, &detail::ref(s));
287  
    authority_view a = grammar::parse(
287  
    authority_view a = grammar::parse(
288  
        s, authority_rule
288  
        s, authority_rule
289  
            ).value(BOOST_URL_POS);
289  
            ).value(BOOST_URL_POS);
290  
    auto n = s.size() + 2;
290  
    auto n = s.size() + 2;
291  
    auto const need_slash =
291  
    auto const need_slash =
292  
        ! is_path_absolute() &&
292  
        ! is_path_absolute() &&
293  
        impl_.len(id_path) > 0;
293  
        impl_.len(id_path) > 0;
294  
    if(need_slash)
294  
    if(need_slash)
295  
        ++n;
295  
        ++n;
296  
    auto dest = resize_impl(
296  
    auto dest = resize_impl(
297  
        id_user, id_path, n, op);
297  
        id_user, id_path, n, op);
298  
    dest[0] = '/';
298  
    dest[0] = '/';
299  
    dest[1] = '/';
299  
    dest[1] = '/';
300  
    std::memcpy(dest + 2,
300  
    std::memcpy(dest + 2,
301  
        s.data(), s.size());
301  
        s.data(), s.size());
302  
    if(need_slash)
302  
    if(need_slash)
303  
        dest[n - 1] = '/';
303  
        dest[n - 1] = '/';
304  
    impl_.apply_authority(a);
304  
    impl_.apply_authority(a);
305  
    if(need_slash)
305  
    if(need_slash)
306  
        impl_.adjust_right(
306  
        impl_.adjust_right(
307  
                id_query, id_end, 1);
307  
                id_query, id_end, 1);
308  
    return *this;
308  
    return *this;
309  
}
309  
}
310  

310  

311  
url_base&
311  
url_base&
312  
url_base::
312  
url_base::
313  
remove_authority()
313  
remove_authority()
314  
{
314  
{
315  
    if(! has_authority())
315  
    if(! has_authority())
316  
        return *this;
316  
        return *this;
317  

317  

318  
    op_t op(*this);
318  
    op_t op(*this);
319  
    auto path = impl_.get(id_path);
319  
    auto path = impl_.get(id_path);
320  
    bool const need_dot = path.starts_with("//");
320  
    bool const need_dot = path.starts_with("//");
321  
    if(need_dot)
321  
    if(need_dot)
322  
    {
322  
    {
323  
        // prepend "/.", can't throw
323  
        // prepend "/.", can't throw
324  
        auto p = resize_impl(
324  
        auto p = resize_impl(
325  
            id_user, id_path, 2, op);
325  
            id_user, id_path, 2, op);
326  
        p[0] = '/';
326  
        p[0] = '/';
327  
        p[1] = '.';
327  
        p[1] = '.';
328  
        impl_.split(id_user, 0);
328  
        impl_.split(id_user, 0);
329  
        impl_.split(id_pass, 0);
329  
        impl_.split(id_pass, 0);
330  
        impl_.split(id_host, 0);
330  
        impl_.split(id_host, 0);
331  
        impl_.split(id_port, 0);
331  
        impl_.split(id_port, 0);
332  
    }
332  
    }
333  
    else
333  
    else
334  
    {
334  
    {
335  
        resize_impl(
335  
        resize_impl(
336  
            id_user, id_path, 0, op);
336  
            id_user, id_path, 0, op);
337  
    }
337  
    }
338  
    impl_.host_type_ =
338  
    impl_.host_type_ =
339  
        urls::host_type::none;
339  
        urls::host_type::none;
340  
    return *this;
340  
    return *this;
341  
}
341  
}
342  

342  

343  
//------------------------------------------------
343  
//------------------------------------------------
344  
//
344  
//
345  
// Userinfo
345  
// Userinfo
346  
//
346  
//
347  
//------------------------------------------------
347  
//------------------------------------------------
348  

348  

349  
url_base&
349  
url_base&
350  
url_base::
350  
url_base::
351  
set_userinfo(
351  
set_userinfo(
352  
    core::string_view s)
352  
    core::string_view s)
353  
{
353  
{
354  
    op_t op(*this, &s);
354  
    op_t op(*this, &s);
355  
    encoding_opts opt;
355  
    encoding_opts opt;
356  
    auto const n = encoded_size(
356  
    auto const n = encoded_size(
357  
        s, detail::userinfo_chars, opt);
357  
        s, detail::userinfo_chars, opt);
358  
    auto dest = set_userinfo_impl(n, op);
358  
    auto dest = set_userinfo_impl(n, op);
359  
    encode(
359  
    encode(
360  
        dest,
360  
        dest,
361  
        n,
361  
        n,
362  
        s,
362  
        s,
363  
        detail::userinfo_chars,
363  
        detail::userinfo_chars,
364  
        opt);
364  
        opt);
365  
    auto const pos = impl_.get(
365  
    auto const pos = impl_.get(
366  
        id_user, id_host
366  
        id_user, id_host
367  
            ).find_first_of(':');
367  
            ).find_first_of(':');
368  
    if(pos != core::string_view::npos)
368  
    if(pos != core::string_view::npos)
369  
    {
369  
    {
370  
        impl_.split(id_user, pos);
370  
        impl_.split(id_user, pos);
371  
        // find ':' in plain string
371  
        // find ':' in plain string
372  
        auto const pos2 =
372  
        auto const pos2 =
373  
            s.find_first_of(':');
373  
            s.find_first_of(':');
374 -
        impl_.decoded_[id_user] =
374 +
        if(pos2 != core::string_view::npos)
375 -
            pos2 - 1;
375 +
        {
376 -
        impl_.decoded_[id_pass] =
376 +
            // pos2 is the ':' index in plain input (user[:pass])
377 -
            s.size() - pos2;
377 +
            // decoded user is [0, pos2), decoded pass is (pos2, end].
 
378 +
            impl_.decoded_[id_user] =
 
379 +
                detail::to_size_type(pos2);
 
380 +
            impl_.decoded_[id_pass] =
 
381 +
                detail::to_size_type(s.size() - pos2 - 1);
 
382 +
        }
 
383 +
        else
 
384 +
        {
 
385 +
            impl_.decoded_[id_user] =
 
386 +
                detail::to_size_type(s.size());
 
387 +
            impl_.decoded_[id_pass] = 0;
 
388 +
        }
378  
    }
389  
    }
379  
    else
390  
    else
380  
    {
391  
    {
381 -
        impl_.decoded_[id_user] = s.size();
392 +
        impl_.decoded_[id_user] =
 
393 +
            detail::to_size_type(s.size());
382  
        impl_.decoded_[id_pass] = 0;
394  
        impl_.decoded_[id_pass] = 0;
383  
    }
395  
    }
384  
    return *this;
396  
    return *this;
385  
}
397  
}
386  

398  

387  
url_base&
399  
url_base&
388  
url_base::
400  
url_base::
389  
set_encoded_userinfo(
401  
set_encoded_userinfo(
390  
    pct_string_view s)
402  
    pct_string_view s)
391  
{
403  
{
392  
    op_t op(*this, &detail::ref(s));
404  
    op_t op(*this, &detail::ref(s));
393  
    auto const pos = s.find_first_of(':');
405  
    auto const pos = s.find_first_of(':');
394  
    if(pos != core::string_view::npos)
406  
    if(pos != core::string_view::npos)
395  
    {
407  
    {
396  
        // user:pass
408  
        // user:pass
397  
        auto const s0 = s.substr(0, pos);
409  
        auto const s0 = s.substr(0, pos);
398  
        auto const s1 = s.substr(pos + 1);
410  
        auto const s1 = s.substr(pos + 1);
399  
        auto const n0 =
411  
        auto const n0 =
400  
            detail::re_encoded_size_unsafe(
412  
            detail::re_encoded_size_unsafe(
401  
                s0,
413  
                s0,
402  
                detail::user_chars);
414  
                detail::user_chars);
403  
        auto const n1 =
415  
        auto const n1 =
404  
            detail::re_encoded_size_unsafe(s1,
416  
            detail::re_encoded_size_unsafe(s1,
405  
                detail::password_chars);
417  
                detail::password_chars);
406  
        auto dest =
418  
        auto dest =
407  
            set_userinfo_impl(n0 + n1 + 1, op);
419  
            set_userinfo_impl(n0 + n1 + 1, op);
408  
        impl_.decoded_[id_user] =
420  
        impl_.decoded_[id_user] =
409 -
            detail::re_encode_unsafe(
421 +
            detail::to_size_type(detail::re_encode_unsafe(
410  
                dest,
422  
                dest,
411  
                dest + n0,
423  
                dest + n0,
412  
                s0,
424  
                s0,
413 -
                detail::user_chars);
425 +
                detail::user_chars));
414  
        *dest++ = ':';
426  
        *dest++ = ':';
415  
        impl_.decoded_[id_pass] =
427  
        impl_.decoded_[id_pass] =
416 -
            detail::re_encode_unsafe(
428 +
            detail::to_size_type(detail::re_encode_unsafe(
417  
                dest,
429  
                dest,
418  
                dest + n1,
430  
                dest + n1,
419  
                s1,
431  
                s1,
420 -
                detail::password_chars);
432 +
                detail::password_chars));
421  
        impl_.split(id_user, 2 + n0);
433  
        impl_.split(id_user, 2 + n0);
422  
    }
434  
    }
423  
    else
435  
    else
424  
    {
436  
    {
425  
        // user
437  
        // user
426  
        auto const n =
438  
        auto const n =
427  
            detail::re_encoded_size_unsafe(
439  
            detail::re_encoded_size_unsafe(
428  
                s, detail::user_chars);
440  
                s, detail::user_chars);
429  
        auto dest = set_userinfo_impl(n, op);
441  
        auto dest = set_userinfo_impl(n, op);
430  
        impl_.decoded_[id_user] =
442  
        impl_.decoded_[id_user] =
431 -
            detail::re_encode_unsafe(
443 +
            detail::to_size_type(detail::re_encode_unsafe(
432  
                dest,
444  
                dest,
433  
                dest + n,
445  
                dest + n,
434  
                s,
446  
                s,
435 -
                detail::user_chars);
447 +
                detail::user_chars));
436  
        impl_.split(id_user, 2 + n);
448  
        impl_.split(id_user, 2 + n);
437  
        impl_.decoded_[id_pass] = 0;
449  
        impl_.decoded_[id_pass] = 0;
438  
    }
450  
    }
439  
    return *this;
451  
    return *this;
440  
}
452  
}
441  

453  

442  
url_base&
454  
url_base&
443  
url_base::
455  
url_base::
444  
remove_userinfo() noexcept
456  
remove_userinfo() noexcept
445  
{
457  
{
446  
    if(impl_.len(id_pass) == 0)
458  
    if(impl_.len(id_pass) == 0)
447  
        return *this; // no userinfo
459  
        return *this; // no userinfo
448  

460  

449  
    op_t op(*this);
461  
    op_t op(*this);
450  
    // keep authority '//'
462  
    // keep authority '//'
451  
    resize_impl(
463  
    resize_impl(
452  
        id_user, id_host, 2, op);
464  
        id_user, id_host, 2, op);
453  
    impl_.decoded_[id_user] = 0;
465  
    impl_.decoded_[id_user] = 0;
454  
    impl_.decoded_[id_pass] = 0;
466  
    impl_.decoded_[id_pass] = 0;
455  
    return *this;
467  
    return *this;
456  
}
468  
}
457  

469  

458  
//------------------------------------------------
470  
//------------------------------------------------
459  

471  

460  
url_base&
472  
url_base&
461  
url_base::
473  
url_base::
462  
set_user(core::string_view s)
474  
set_user(core::string_view s)
463  
{
475  
{
464  
    op_t op(*this, &s);
476  
    op_t op(*this, &s);
465  
    encoding_opts opt;
477  
    encoding_opts opt;
466  
    auto const n = encoded_size(
478  
    auto const n = encoded_size(
467  
        s, detail::user_chars, opt);
479  
        s, detail::user_chars, opt);
468  
    auto dest = set_user_impl(n, op);
480  
    auto dest = set_user_impl(n, op);
469  
    encode_unsafe(
481  
    encode_unsafe(
470  
        dest,
482  
        dest,
471  
        n,
483  
        n,
472  
        s,
484  
        s,
473  
        detail::user_chars,
485  
        detail::user_chars,
474  
        opt);
486  
        opt);
475 -
    impl_.decoded_[id_user] = s.size();
487 +
    impl_.decoded_[id_user] =
 
488 +
        detail::to_size_type(s.size());
476  
    return *this;
489  
    return *this;
477  
}
490  
}
478  

491  

479  
url_base&
492  
url_base&
480  
url_base::
493  
url_base::
481  
set_encoded_user(
494  
set_encoded_user(
482  
    pct_string_view s)
495  
    pct_string_view s)
483  
{
496  
{
484  
    op_t op(*this, &detail::ref(s));
497  
    op_t op(*this, &detail::ref(s));
485  
    auto const n =
498  
    auto const n =
486  
        detail::re_encoded_size_unsafe(
499  
        detail::re_encoded_size_unsafe(
487  
            s, detail::user_chars);
500  
            s, detail::user_chars);
488  
    auto dest = set_user_impl(n, op);
501  
    auto dest = set_user_impl(n, op);
489  
    impl_.decoded_[id_user] =
502  
    impl_.decoded_[id_user] =
490 -
        detail::re_encode_unsafe(
503 +
        detail::to_size_type(detail::re_encode_unsafe(
491  
            dest,
504  
            dest,
492  
            dest + n,
505  
            dest + n,
493  
            s,
506  
            s,
494 -
            detail::user_chars);
507 +
            detail::user_chars));
495  
    BOOST_ASSERT(
508  
    BOOST_ASSERT(
496  
        impl_.decoded_[id_user] ==
509  
        impl_.decoded_[id_user] ==
497  
            s.decoded_size());
510  
            s.decoded_size());
498  
    return *this;
511  
    return *this;
499  
}
512  
}
500  

513  

501  
//------------------------------------------------
514  
//------------------------------------------------
502  

515  

503  
url_base&
516  
url_base&
504  
url_base::
517  
url_base::
505  
set_password(core::string_view s)
518  
set_password(core::string_view s)
506  
{
519  
{
507  
    op_t op(*this, &s);
520  
    op_t op(*this, &s);
508  
    encoding_opts opt;
521  
    encoding_opts opt;
509  
    auto const n = encoded_size(
522  
    auto const n = encoded_size(
510  
        s, detail::password_chars, opt);
523  
        s, detail::password_chars, opt);
511  
    auto dest = set_password_impl(n, op);
524  
    auto dest = set_password_impl(n, op);
512  
    encode_unsafe(
525  
    encode_unsafe(
513  
        dest,
526  
        dest,
514  
        n,
527  
        n,
515  
        s,
528  
        s,
516  
        detail::password_chars,
529  
        detail::password_chars,
517  
        opt);
530  
        opt);
518 -
    impl_.decoded_[id_pass] = s.size();
531 +
    impl_.decoded_[id_pass] =
 
532 +
        detail::to_size_type(s.size());
519  
    return *this;
533  
    return *this;
520  
}
534  
}
521  

535  

522  
url_base&
536  
url_base&
523  
url_base::
537  
url_base::
524  
set_encoded_password(
538  
set_encoded_password(
525  
    pct_string_view s)
539  
    pct_string_view s)
526  
{
540  
{
527  
    op_t op(*this, &detail::ref(s));
541  
    op_t op(*this, &detail::ref(s));
528  
    auto const n =
542  
    auto const n =
529  
        detail::re_encoded_size_unsafe(
543  
        detail::re_encoded_size_unsafe(
530  
            s,
544  
            s,
531  
            detail::password_chars);
545  
            detail::password_chars);
532  
    auto dest = set_password_impl(n, op);
546  
    auto dest = set_password_impl(n, op);
533  
    impl_.decoded_[id_pass] =
547  
    impl_.decoded_[id_pass] =
534 -
        detail::re_encode_unsafe(
548 +
        detail::to_size_type(detail::re_encode_unsafe(
535  
            dest,
549  
            dest,
536  
            dest + n,
550  
            dest + n,
537  
            s,
551  
            s,
538 -
            detail::password_chars);
552 +
            detail::password_chars));
539  
    BOOST_ASSERT(
553  
    BOOST_ASSERT(
540  
        impl_.decoded_[id_pass] ==
554  
        impl_.decoded_[id_pass] ==
541  
            s.decoded_size());
555  
            s.decoded_size());
542  
    return *this;
556  
    return *this;
543  
}
557  
}
544  

558  

545  
url_base&
559  
url_base&
546  
url_base::
560  
url_base::
547  
remove_password() noexcept
561  
remove_password() noexcept
548  
{
562  
{
549  
    auto const n = impl_.len(id_pass);
563  
    auto const n = impl_.len(id_pass);
550  
    if(n < 2)
564  
    if(n < 2)
551  
        return *this; // no password
565  
        return *this; // no password
552  

566  

553  
    op_t op(*this);
567  
    op_t op(*this);
554  
    // clear password, retain '@'
568  
    // clear password, retain '@'
555  
    auto dest =
569  
    auto dest =
556  
        resize_impl(id_pass, 1, op);
570  
        resize_impl(id_pass, 1, op);
557  
    dest[0] = '@';
571  
    dest[0] = '@';
558  
    impl_.decoded_[id_pass] = 0;
572  
    impl_.decoded_[id_pass] = 0;
559  
    return *this;
573  
    return *this;
560  
}
574  
}
561  

575  

562  
//------------------------------------------------
576  
//------------------------------------------------
563  
//
577  
//
564  
// Host
578  
// Host
565  
//
579  
//
566  
//------------------------------------------------
580  
//------------------------------------------------
567  
/*
581  
/*
568  
host_type       host_type()                 // ipv4, ipv6, ipvfuture, name
582  
host_type       host_type()                 // ipv4, ipv6, ipvfuture, name
569  

583  

570  
std::string     host()                      // return encoded_host().decode()
584  
std::string     host()                      // return encoded_host().decode()
571  
pct_string_view encoded_host()              // return host part, as-is
585  
pct_string_view encoded_host()              // return host part, as-is
572  
std::string     host_address()              // return encoded_host_address().decode()
586  
std::string     host_address()              // return encoded_host_address().decode()
573  
pct_string_view encoded_host_address()      // ipv4, ipv6, ipvfut, or encoded name, no brackets
587  
pct_string_view encoded_host_address()      // ipv4, ipv6, ipvfut, or encoded name, no brackets
574  

588  

575  
ipv4_address    host_ipv4_address()         // return ipv4_address or {}
589  
ipv4_address    host_ipv4_address()         // return ipv4_address or {}
576  
ipv6_address    host_ipv6_address()         // return ipv6_address or {}
590  
ipv6_address    host_ipv6_address()         // return ipv6_address or {}
577  
core::string_view     host_ipvfuture()            // return ipvfuture or {}
591  
core::string_view     host_ipvfuture()            // return ipvfuture or {}
578  
std::string     host_name()                 // return decoded name or ""
592  
std::string     host_name()                 // return decoded name or ""
579  
pct_string_view encoded_host_name()         // return encoded host name or ""
593  
pct_string_view encoded_host_name()         // return encoded host name or ""
580  

594  

581  
--------------------------------------------------
595  
--------------------------------------------------
582  

596  

583  
set_host( core::string_view )                     // set host part from plain text
597  
set_host( core::string_view )                     // set host part from plain text
584  
set_encoded_host( pct_string_view )         // set host part from encoded text
598  
set_encoded_host( pct_string_view )         // set host part from encoded text
585  
set_host_address( core::string_view )             // set host from ipv4, ipv6, ipvfut, or plain reg-name string
599  
set_host_address( core::string_view )             // set host from ipv4, ipv6, ipvfut, or plain reg-name string
586  
set_encoded_host_address( pct_string_view ) // set host from ipv4, ipv6, ipvfut, or encoded reg-name string
600  
set_encoded_host_address( pct_string_view ) // set host from ipv4, ipv6, ipvfut, or encoded reg-name string
587  

601  

588  
set_host_ipv4( ipv4_address )               // set ipv4
602  
set_host_ipv4( ipv4_address )               // set ipv4
589  
set_host_ipv6( ipv6_address )               // set ipv6
603  
set_host_ipv6( ipv6_address )               // set ipv6
590  
set_host_ipvfuture( core::string_view )           // set ipvfuture
604  
set_host_ipvfuture( core::string_view )           // set ipvfuture
591  
set_host_name( core::string_view )                // set name from plain
605  
set_host_name( core::string_view )                // set name from plain
592  
set_encoded_host_name( pct_string_view )    // set name from encoded
606  
set_encoded_host_name( pct_string_view )    // set name from encoded
593  
*/
607  
*/
594  

608  

595  
// set host part from plain text
609  
// set host part from plain text
596  
url_base&
610  
url_base&
597  
url_base::
611  
url_base::
598  
set_host(
612  
set_host(
599  
    core::string_view s)
613  
    core::string_view s)
600  
{
614  
{
601  
    if( s.size() > 2 &&
615  
    if( s.size() > 2 &&
602  
        s.front() == '[' &&
616  
        s.front() == '[' &&
603  
        s.back() == ']')
617  
        s.back() == ']')
604  
    {
618  
    {
605  
        // IP-literal
619  
        // IP-literal
606  
        if (s[1] != 'v')
620  
        if (s[1] != 'v')
607  
        {
621  
        {
608  
            // IPv6-address
622  
            // IPv6-address
609  
            auto innersv = s.substr(1, s.size() - 2);
623  
            auto innersv = s.substr(1, s.size() - 2);
610  
            auto innerit = innersv.begin();
624  
            auto innerit = innersv.begin();
611  
            auto endit = innersv.end();
625  
            auto endit = innersv.end();
612  
            auto rv = grammar::parse(
626  
            auto rv = grammar::parse(
613  
                innerit,
627  
                innerit,
614  
                endit,
628  
                endit,
615  
                ipv6_address_rule);
629  
                ipv6_address_rule);
616  
            if(rv)
630  
            if(rv)
617  
            {
631  
            {
618  
                if (innerit == endit)
632  
                if (innerit == endit)
619  
                {
633  
                {
620  
                    set_host_ipv6_and_encoded_zone_id(*rv, {});
634  
                    set_host_ipv6_and_encoded_zone_id(*rv, {});
621  
                    return *this;
635  
                    return *this;
622  
                }
636  
                }
623  
                // IPv6addrz: https://datatracker.ietf.org/doc/html/rfc6874
637  
                // IPv6addrz: https://datatracker.ietf.org/doc/html/rfc6874
624  
                auto chars_left = endit - innerit;
638  
                auto chars_left = endit - innerit;
625  
                if (chars_left >= 2 &&
639  
                if (chars_left >= 2 &&
626  
                    *innerit++ == '%')
640  
                    *innerit++ == '%')
627  
                {
641  
                {
628  
                    core::string_view zone_id_str = {&*innerit, std::size_t(chars_left - 1)};
642  
                    core::string_view zone_id_str = {&*innerit, std::size_t(chars_left - 1)};
629  
                    set_host_ipv6_and_zone_id(*rv, zone_id_str);
643  
                    set_host_ipv6_and_zone_id(*rv, zone_id_str);
630  
                    return *this;
644  
                    return *this;
631  
                }
645  
                }
632  
            }
646  
            }
633  
        }
647  
        }
634  
        else
648  
        else
635  
        {
649  
        {
636  
            // IPvFuture
650  
            // IPvFuture
637  
            auto rv = grammar::parse(
651  
            auto rv = grammar::parse(
638  
                s.substr(1, s.size() - 2),
652  
                s.substr(1, s.size() - 2),
639  
                detail::ipvfuture_rule);
653  
                detail::ipvfuture_rule);
640  
            if(rv)
654  
            if(rv)
641  
                return set_host_ipvfuture(rv->str);
655  
                return set_host_ipvfuture(rv->str);
642  
        }
656  
        }
643  
    }
657  
    }
644  
    else if(s.size() >= 7) // "0.0.0.0"
658  
    else if(s.size() >= 7) // "0.0.0.0"
645  
    {
659  
    {
646  
        // IPv4-address
660  
        // IPv4-address
647  
        auto rv = parse_ipv4_address(s);
661  
        auto rv = parse_ipv4_address(s);
648  
        if(rv)
662  
        if(rv)
649  
            return set_host_ipv4(*rv);
663  
            return set_host_ipv4(*rv);
650  
    }
664  
    }
651  

665  

652  
    // reg-name
666  
    // reg-name
653  
    op_t op(*this, &s);
667  
    op_t op(*this, &s);
654  
    encoding_opts opt;
668  
    encoding_opts opt;
655  
    auto const n = encoded_size(
669  
    auto const n = encoded_size(
656  
        s, detail::host_chars, opt);
670  
        s, detail::host_chars, opt);
657  
    auto dest = set_host_impl(n, op);
671  
    auto dest = set_host_impl(n, op);
658  
    encode(
672  
    encode(
659  
        dest,
673  
        dest,
660  
        impl_.get(id_path).data() - dest,
674  
        impl_.get(id_path).data() - dest,
661  
        s,
675  
        s,
662  
        detail::host_chars,
676  
        detail::host_chars,
663  
        opt);
677  
        opt);
664 -
    impl_.decoded_[id_host] = s.size();
678 +
    impl_.decoded_[id_host] =
 
679 +
        detail::to_size_type(s.size());
665  
    impl_.host_type_ =
680  
    impl_.host_type_ =
666  
        urls::host_type::name;
681  
        urls::host_type::name;
667  
    return *this;
682  
    return *this;
668  
}
683  
}
669  

684  

670  
// set host part from encoded text
685  
// set host part from encoded text
671  
url_base&
686  
url_base&
672  
url_base::
687  
url_base::
673  
set_encoded_host(
688  
set_encoded_host(
674  
    pct_string_view s)
689  
    pct_string_view s)
675  
{
690  
{
676  
    if( s.size() > 2 &&
691  
    if( s.size() > 2 &&
677  
        s.front() == '[' &&
692  
        s.front() == '[' &&
678  
        s.back() == ']')
693  
        s.back() == ']')
679  
    {
694  
    {
680  
        // IP-literal
695  
        // IP-literal
681  
        if (s[1] != 'v')
696  
        if (s[1] != 'v')
682  
        {
697  
        {
683  
            // IPv6-address
698  
            // IPv6-address
684  
            auto innersv = s.substr(1, s.size() - 2);
699  
            auto innersv = s.substr(1, s.size() - 2);
685  
            auto innerit = innersv.begin();
700  
            auto innerit = innersv.begin();
686  
            auto endit = innersv.end();
701  
            auto endit = innersv.end();
687  
            auto rv = grammar::parse(
702  
            auto rv = grammar::parse(
688  
                innerit,
703  
                innerit,
689  
                endit,
704  
                endit,
690  
                ipv6_address_rule);
705  
                ipv6_address_rule);
691  
            if(rv)
706  
            if(rv)
692  
            {
707  
            {
693  
                if (innerit == endit)
708  
                if (innerit == endit)
694  
                {
709  
                {
695  
                    set_host_ipv6_and_encoded_zone_id(*rv, {});
710  
                    set_host_ipv6_and_encoded_zone_id(*rv, {});
696  
                    return *this;
711  
                    return *this;
697  
                }
712  
                }
698  
                // IPv6addrz: https://datatracker.ietf.org/doc/html/rfc6874
713  
                // IPv6addrz: https://datatracker.ietf.org/doc/html/rfc6874
699  
                auto chars_left = endit - innerit;
714  
                auto chars_left = endit - innerit;
700  
                if (chars_left >= 3 &&
715  
                if (chars_left >= 3 &&
701  
                    *innerit++ == '%' &&
716  
                    *innerit++ == '%' &&
702  
                    *innerit++ == '2' &&
717  
                    *innerit++ == '2' &&
703  
                    *innerit++ == '5')
718  
                    *innerit++ == '5')
704  
                {
719  
                {
705  
                    auto const nz = std::size_t(chars_left - 3);
720  
                    auto const nz = std::size_t(chars_left - 3);
706  
                    core::string_view zone_id_str = {&*innerit, std::size_t(chars_left - 3)};
721  
                    core::string_view zone_id_str = {&*innerit, std::size_t(chars_left - 3)};
707  
                    std::size_t dnz = detail::decode_bytes_unsafe(zone_id_str);
722  
                    std::size_t dnz = detail::decode_bytes_unsafe(zone_id_str);
708  
                    pct_string_view zone_id_pct = make_pct_string_view_unsafe(innerit, nz, dnz);
723  
                    pct_string_view zone_id_pct = make_pct_string_view_unsafe(innerit, nz, dnz);
709  
                    set_host_ipv6_and_encoded_zone_id(*rv, zone_id_pct);
724  
                    set_host_ipv6_and_encoded_zone_id(*rv, zone_id_pct);
710  
                    return *this;
725  
                    return *this;
711  
                }
726  
                }
712  
            }
727  
            }
713  
        }
728  
        }
714  
        else
729  
        else
715  
        {
730  
        {
716  
            // IPvFuture
731  
            // IPvFuture
717  
            auto rv = grammar::parse(
732  
            auto rv = grammar::parse(
718  
                s.substr(1, s.size() - 2),
733  
                s.substr(1, s.size() - 2),
719  
                    detail::ipvfuture_rule);
734  
                    detail::ipvfuture_rule);
720  
            if(rv)
735  
            if(rv)
721  
                return set_host_ipvfuture(rv->str);
736  
                return set_host_ipvfuture(rv->str);
722  
        }
737  
        }
723  
    }
738  
    }
724  
    else if(s.size() >= 7) // "0.0.0.0"
739  
    else if(s.size() >= 7) // "0.0.0.0"
725  
    {
740  
    {
726  
        // IPv4-address
741  
        // IPv4-address
727  
        auto rv = parse_ipv4_address(s);
742  
        auto rv = parse_ipv4_address(s);
728  
        if(rv)
743  
        if(rv)
729  
            return set_host_ipv4(*rv);
744  
            return set_host_ipv4(*rv);
730  
    }
745  
    }
731  

746  

732  
    // reg-name
747  
    // reg-name
733  
    op_t op(*this, &detail::ref(s));
748  
    op_t op(*this, &detail::ref(s));
734  
    auto const n = detail::re_encoded_size_unsafe(
749  
    auto const n = detail::re_encoded_size_unsafe(
735  
        s, detail::host_chars);
750  
        s, detail::host_chars);
736  
    auto dest = set_host_impl(n, op);
751  
    auto dest = set_host_impl(n, op);
737  
    impl_.decoded_[id_host] =
752  
    impl_.decoded_[id_host] =
738 -
        detail::re_encode_unsafe(
753 +
        detail::to_size_type(detail::re_encode_unsafe(
739  
            dest,
754  
            dest,
740  
            impl_.get(id_path).data(),
755  
            impl_.get(id_path).data(),
741  
            s,
756  
            s,
742 -
            detail::host_chars);
757 +
            detail::host_chars));
743  
    BOOST_ASSERT(impl_.decoded_[id_host] ==
758  
    BOOST_ASSERT(impl_.decoded_[id_host] ==
744  
        s.decoded_size());
759  
        s.decoded_size());
745  
    impl_.host_type_ =
760  
    impl_.host_type_ =
746  
        urls::host_type::name;
761  
        urls::host_type::name;
747  
    return *this;
762  
    return *this;
748  
}
763  
}
749  

764  

750  
url_base&
765  
url_base&
751  
url_base::
766  
url_base::
752  
set_host_address(
767  
set_host_address(
753  
    core::string_view s)
768  
    core::string_view s)
754  
{
769  
{
755  
    if (!s.empty())
770  
    if (!s.empty())
756  
    {
771  
    {
757  
        // IP-literal
772  
        // IP-literal
758  
        if (s[0] != 'v')
773  
        if (s[0] != 'v')
759  
        {
774  
        {
760  
            // IPv6-address
775  
            // IPv6-address
761  
            auto innerit = s.begin();
776  
            auto innerit = s.begin();
762  
            auto endit = s.end();
777  
            auto endit = s.end();
763  
            auto rv = grammar::parse(
778  
            auto rv = grammar::parse(
764  
                innerit,
779  
                innerit,
765  
                endit,
780  
                endit,
766  
                ipv6_address_rule);
781  
                ipv6_address_rule);
767  
            if(rv)
782  
            if(rv)
768  
            {
783  
            {
769  
                if (innerit == endit)
784  
                if (innerit == endit)
770  
                {
785  
                {
771  
                    set_host_ipv6_and_encoded_zone_id(*rv, {});
786  
                    set_host_ipv6_and_encoded_zone_id(*rv, {});
772  
                    return *this;
787  
                    return *this;
773  
                }
788  
                }
774  
                // IPv6addrz: https://datatracker.ietf.org/doc/html/rfc6874
789  
                // IPv6addrz: https://datatracker.ietf.org/doc/html/rfc6874
775  
                auto chars_left = endit - innerit;
790  
                auto chars_left = endit - innerit;
776  
                if (chars_left >= 2 &&
791  
                if (chars_left >= 2 &&
777  
                    *innerit++ == '%')
792  
                    *innerit++ == '%')
778  
                {
793  
                {
779  
                    core::string_view zone_id_str = {&*innerit, std::size_t(chars_left - 1)};
794  
                    core::string_view zone_id_str = {&*innerit, std::size_t(chars_left - 1)};
780  
                    set_host_ipv6_and_zone_id(*rv, zone_id_str);
795  
                    set_host_ipv6_and_zone_id(*rv, zone_id_str);
781  
                    return *this;
796  
                    return *this;
782  
                }
797  
                }
783  
            }
798  
            }
784  
        }
799  
        }
785  

800  

786  
        // IPvFuture
801  
        // IPvFuture
787  
        auto rv = grammar::parse(s, detail::ipvfuture_rule);
802  
        auto rv = grammar::parse(s, detail::ipvfuture_rule);
788  
        if(rv)
803  
        if(rv)
789  
            return set_host_ipvfuture(rv->str);
804  
            return set_host_ipvfuture(rv->str);
790  

805  

791  
        if(s.size() >= 7) // "0.0.0.0"
806  
        if(s.size() >= 7) // "0.0.0.0"
792  
        {
807  
        {
793  
            // IPv4-address
808  
            // IPv4-address
794  
            auto rv2 = parse_ipv4_address(s);
809  
            auto rv2 = parse_ipv4_address(s);
795  
            if(rv2)
810  
            if(rv2)
796  
                return set_host_ipv4(*rv2);
811  
                return set_host_ipv4(*rv2);
797  
        }
812  
        }
798  
    }
813  
    }
799  

814  

800  
    // reg-name
815  
    // reg-name
801  
    op_t op(*this, &s);
816  
    op_t op(*this, &s);
802  
    encoding_opts opt;
817  
    encoding_opts opt;
803  
    auto const n = encoded_size(
818  
    auto const n = encoded_size(
804  
        s, detail::host_chars, opt);
819  
        s, detail::host_chars, opt);
805  
    auto dest = set_host_impl(n, op);
820  
    auto dest = set_host_impl(n, op);
806  
    encode(
821  
    encode(
807  
        dest,
822  
        dest,
808  
        impl_.get(id_path).data() - dest,
823  
        impl_.get(id_path).data() - dest,
809  
        s,
824  
        s,
810  
        detail::host_chars,
825  
        detail::host_chars,
811  
        opt);
826  
        opt);
812 -
    impl_.decoded_[id_host] = s.size();
827 +
    impl_.decoded_[id_host] =
 
828 +
        detail::to_size_type(s.size());
813  
    impl_.host_type_ =
829  
    impl_.host_type_ =
814  
        urls::host_type::name;
830  
        urls::host_type::name;
815  
    return *this;
831  
    return *this;
816  
}
832  
}
817  

833  

818  
url_base&
834  
url_base&
819  
url_base::
835  
url_base::
820  
set_encoded_host_address(
836  
set_encoded_host_address(
821  
    pct_string_view s)
837  
    pct_string_view s)
822  
{
838  
{
823  
    if( !s.empty() )
839  
    if( !s.empty() )
824  
    {
840  
    {
825  
        // IP-literal
841  
        // IP-literal
826  
        if (s[0] != 'v')
842  
        if (s[0] != 'v')
827  
        {
843  
        {
828  
            // IPv6-address
844  
            // IPv6-address
829  
            auto innerit = s.begin();
845  
            auto innerit = s.begin();
830  
            auto endit = s.end();
846  
            auto endit = s.end();
831  
            auto rv = grammar::parse(
847  
            auto rv = grammar::parse(
832  
                innerit,
848  
                innerit,
833  
                endit,
849  
                endit,
834  
                ipv6_address_rule);
850  
                ipv6_address_rule);
835  
            if(rv)
851  
            if(rv)
836  
            {
852  
            {
837  
                if (innerit == endit)
853  
                if (innerit == endit)
838  
                {
854  
                {
839  
                    set_host_ipv6_and_encoded_zone_id(*rv, {});
855  
                    set_host_ipv6_and_encoded_zone_id(*rv, {});
840  
                    return *this;
856  
                    return *this;
841  
                }
857  
                }
842  
                // IPv6addrz: https://datatracker.ietf.org/doc/html/rfc6874
858  
                // IPv6addrz: https://datatracker.ietf.org/doc/html/rfc6874
843  
                auto chars_left = endit - innerit;
859  
                auto chars_left = endit - innerit;
844  
                if (chars_left >= 3 &&
860  
                if (chars_left >= 3 &&
845  
                    *innerit++ == '%' &&
861  
                    *innerit++ == '%' &&
846  
                    *innerit++ == '2' &&
862  
                    *innerit++ == '2' &&
847  
                    *innerit++ == '5')
863  
                    *innerit++ == '5')
848  
                {
864  
                {
849  
                    auto const nz = std::size_t(chars_left - 3);
865  
                    auto const nz = std::size_t(chars_left - 3);
850  
                    core::string_view zone_id_str = {&*innerit, std::size_t(chars_left - 3)};
866  
                    core::string_view zone_id_str = {&*innerit, std::size_t(chars_left - 3)};
851  
                    std::size_t dnz = detail::decode_bytes_unsafe(zone_id_str);
867  
                    std::size_t dnz = detail::decode_bytes_unsafe(zone_id_str);
852  
                    pct_string_view zone_id_pct = make_pct_string_view_unsafe(innerit, nz, dnz);
868  
                    pct_string_view zone_id_pct = make_pct_string_view_unsafe(innerit, nz, dnz);
853  
                    set_host_ipv6_and_encoded_zone_id(*rv, zone_id_pct);
869  
                    set_host_ipv6_and_encoded_zone_id(*rv, zone_id_pct);
854  
                    return *this;
870  
                    return *this;
855  
                }
871  
                }
856  
            }
872  
            }
857  

873  

858  
            if(s.size() >= 7) // "0.0.0.0"
874  
            if(s.size() >= 7) // "0.0.0.0"
859  
            {
875  
            {
860  
                // IPv4-address
876  
                // IPv4-address
861  
                auto rv2 = parse_ipv4_address(s);
877  
                auto rv2 = parse_ipv4_address(s);
862  
                if(rv2)
878  
                if(rv2)
863  
                   return set_host_ipv4(*rv2);
879  
                   return set_host_ipv4(*rv2);
864  
            }
880  
            }
865  
        }
881  
        }
866  
        else
882  
        else
867  
        {
883  
        {
868  
            // IPvFuture
884  
            // IPvFuture
869  
            auto rv = grammar::parse(
885  
            auto rv = grammar::parse(
870  
                s, detail::ipvfuture_rule);
886  
                s, detail::ipvfuture_rule);
871  
            if(rv)
887  
            if(rv)
872  
                return set_host_ipvfuture(rv->str);
888  
                return set_host_ipvfuture(rv->str);
873  
        }
889  
        }
874  
    }
890  
    }
875  

891  

876  
    // reg-name
892  
    // reg-name
877  
    op_t op(*this, &detail::ref(s));
893  
    op_t op(*this, &detail::ref(s));
878  
    auto const n = detail::re_encoded_size_unsafe(
894  
    auto const n = detail::re_encoded_size_unsafe(
879  
        s, detail::host_chars);
895  
        s, detail::host_chars);
880  
    auto dest = set_host_impl(n, op);
896  
    auto dest = set_host_impl(n, op);
881  
    impl_.decoded_[id_host] =
897  
    impl_.decoded_[id_host] =
882 -
        detail::re_encode_unsafe(
898 +
        detail::to_size_type(detail::re_encode_unsafe(
883  
            dest,
899  
            dest,
884  
            impl_.get(id_path).data(),
900  
            impl_.get(id_path).data(),
885  
            s,
901  
            s,
886 -
            detail::host_chars);
902 +
            detail::host_chars));
887  
    BOOST_ASSERT(impl_.decoded_[id_host] ==
903  
    BOOST_ASSERT(impl_.decoded_[id_host] ==
888  
        s.decoded_size());
904  
        s.decoded_size());
889  
    impl_.host_type_ =
905  
    impl_.host_type_ =
890  
        urls::host_type::name;
906  
        urls::host_type::name;
891  
    return *this;
907  
    return *this;
892  
}
908  
}
893  

909  

894  
url_base&
910  
url_base&
895  
url_base::
911  
url_base::
896  
set_host_ipv4(
912  
set_host_ipv4(
897  
    ipv4_address const& addr)
913  
    ipv4_address const& addr)
898  
{
914  
{
899  
    op_t op(*this);
915  
    op_t op(*this);
900  
    char buf[urls::ipv4_address::max_str_len];
916  
    char buf[urls::ipv4_address::max_str_len];
901  
    auto s = addr.to_buffer(buf, sizeof(buf));
917  
    auto s = addr.to_buffer(buf, sizeof(buf));
902  
    auto dest = set_host_impl(s.size(), op);
918  
    auto dest = set_host_impl(s.size(), op);
903  
    std::memcpy(dest, s.data(), s.size());
919  
    std::memcpy(dest, s.data(), s.size());
904 -
    impl_.decoded_[id_host] = impl_.len(id_host);
920 +
    impl_.decoded_[id_host] =
 
921 +
        detail::to_size_type(impl_.len(id_host));
905  
    impl_.host_type_ = urls::host_type::ipv4;
922  
    impl_.host_type_ = urls::host_type::ipv4;
906  
    auto bytes = addr.to_bytes();
923  
    auto bytes = addr.to_bytes();
907  
    std::memcpy(
924  
    std::memcpy(
908  
        impl_.ip_addr_,
925  
        impl_.ip_addr_,
909  
        bytes.data(),
926  
        bytes.data(),
910  
        bytes.size());
927  
        bytes.size());
911  
    return *this;
928  
    return *this;
912  
}
929  
}
913  

930  

914  
url_base&
931  
url_base&
915  
url_base::
932  
url_base::
916  
set_host_ipv6(
933  
set_host_ipv6(
917  
    ipv6_address const& addr)
934  
    ipv6_address const& addr)
918  
{
935  
{
919  
    set_host_ipv6_and_encoded_zone_id(addr, encoded_zone_id());
936  
    set_host_ipv6_and_encoded_zone_id(addr, encoded_zone_id());
920  
    return *this;
937  
    return *this;
921  
}
938  
}
922  

939  

923  
url_base&
940  
url_base&
924  
url_base::
941  
url_base::
925  
set_zone_id(core::string_view s)
942  
set_zone_id(core::string_view s)
926  
{
943  
{
927  
    set_host_ipv6_and_zone_id(host_ipv6_address(), s);
944  
    set_host_ipv6_and_zone_id(host_ipv6_address(), s);
928  
    return *this;
945  
    return *this;
929  
}
946  
}
930  

947  

931  
url_base&
948  
url_base&
932  
url_base::
949  
url_base::
933  
set_encoded_zone_id(pct_string_view s)
950  
set_encoded_zone_id(pct_string_view s)
934  
{
951  
{
935  
    set_host_ipv6_and_encoded_zone_id(host_ipv6_address(), s);
952  
    set_host_ipv6_and_encoded_zone_id(host_ipv6_address(), s);
936  
    return *this;
953  
    return *this;
937  
}
954  
}
938  

955  

939  
void
956  
void
940  
url_base::
957  
url_base::
941  
set_host_ipv6_and_zone_id(
958  
set_host_ipv6_and_zone_id(
942  
    ipv6_address const& addr,
959  
    ipv6_address const& addr,
943  
    core::string_view zone_id)
960  
    core::string_view zone_id)
944  
{
961  
{
945  
    op_t op(*this, &zone_id);
962  
    op_t op(*this, &zone_id);
946  
    char ipv6_str_buf[urls::ipv6_address::max_str_len];
963  
    char ipv6_str_buf[urls::ipv6_address::max_str_len];
947  
    auto ipv6_str = addr.to_buffer(ipv6_str_buf, sizeof(ipv6_str_buf));
964  
    auto ipv6_str = addr.to_buffer(ipv6_str_buf, sizeof(ipv6_str_buf));
948  
    bool const has_zone_id = !zone_id.empty();
965  
    bool const has_zone_id = !zone_id.empty();
949  
    encoding_opts opt;
966  
    encoding_opts opt;
950  
    auto const ipn = ipv6_str.size();
967  
    auto const ipn = ipv6_str.size();
951  
    auto const zn = encoded_size(zone_id, unreserved_chars, opt);
968  
    auto const zn = encoded_size(zone_id, unreserved_chars, opt);
952  
    auto const n = ipn + 2 + has_zone_id * (3 + zn);
969  
    auto const n = ipn + 2 + has_zone_id * (3 + zn);
953  
    auto dest = set_host_impl(n, op);
970  
    auto dest = set_host_impl(n, op);
954  
    *dest++ = '[';
971  
    *dest++ = '[';
955  
    std::memcpy(dest, ipv6_str.data(), ipn);
972  
    std::memcpy(dest, ipv6_str.data(), ipn);
956  
    dest += ipn;
973  
    dest += ipn;
957  
    if (has_zone_id)
974  
    if (has_zone_id)
958  
    {
975  
    {
959  
        *dest++ = '%';
976  
        *dest++ = '%';
960  
        *dest++ = '2';
977  
        *dest++ = '2';
961  
        *dest++ = '5';
978  
        *dest++ = '5';
962  
        encode(dest, zn, zone_id, unreserved_chars, opt);
979  
        encode(dest, zn, zone_id, unreserved_chars, opt);
963  
        dest += zn;
980  
        dest += zn;
964  
    }
981  
    }
965  
    *dest++ = ']';
982  
    *dest++ = ']';
966  
    // ipn + |"["| + |"]"| + (has_zone_id ? |"%"| + zn : 0)
983  
    // ipn + |"["| + |"]"| + (has_zone_id ? |"%"| + zn : 0)
967 -
    impl_.decoded_[id_host] = ipn + 2 + has_zone_id * (1 + zone_id.size());
984 +
    impl_.decoded_[id_host] = detail::to_size_type(
 
985 +
        ipn + 2 + has_zone_id * (1 + zone_id.size()));
968  
    impl_.host_type_ = urls::host_type::ipv6;
986  
    impl_.host_type_ = urls::host_type::ipv6;
969  
    auto bytes = addr.to_bytes();
987  
    auto bytes = addr.to_bytes();
970  
    std::memcpy(
988  
    std::memcpy(
971  
        impl_.ip_addr_,
989  
        impl_.ip_addr_,
972  
        bytes.data(),
990  
        bytes.data(),
973  
        bytes.size());
991  
        bytes.size());
974  
}
992  
}
975  

993  

976  
void
994  
void
977  
url_base::
995  
url_base::
978  
set_host_ipv6_and_encoded_zone_id(
996  
set_host_ipv6_and_encoded_zone_id(
979  
    ipv6_address const& addr,
997  
    ipv6_address const& addr,
980  
    pct_string_view zone_id)
998  
    pct_string_view zone_id)
981  
{
999  
{
982  
    op_t op(*this, &detail::ref(zone_id));
1000  
    op_t op(*this, &detail::ref(zone_id));
983  
    char ipv6_str_buf[urls::ipv6_address::max_str_len];
1001  
    char ipv6_str_buf[urls::ipv6_address::max_str_len];
984  
    auto ipv6_str = addr.to_buffer(ipv6_str_buf, sizeof(ipv6_str_buf));
1002  
    auto ipv6_str = addr.to_buffer(ipv6_str_buf, sizeof(ipv6_str_buf));
985  
    bool const has_zone_id = !zone_id.empty();
1003  
    bool const has_zone_id = !zone_id.empty();
986  
    auto const ipn = ipv6_str.size();
1004  
    auto const ipn = ipv6_str.size();
987  
    auto const zn = detail::re_encoded_size_unsafe(zone_id, unreserved_chars);
1005  
    auto const zn = detail::re_encoded_size_unsafe(zone_id, unreserved_chars);
988  
    auto const n = ipn + 2 + has_zone_id * (3 + zn);
1006  
    auto const n = ipn + 2 + has_zone_id * (3 + zn);
989  
    auto dest = set_host_impl(n, op);
1007  
    auto dest = set_host_impl(n, op);
990  
    *dest++ = '[';
1008  
    *dest++ = '[';
991  
    std::memcpy(dest, ipv6_str.data(), ipn);
1009  
    std::memcpy(dest, ipv6_str.data(), ipn);
992  
    dest += ipn;
1010  
    dest += ipn;
993  
    std::size_t dzn = 0;
1011  
    std::size_t dzn = 0;
994  
    if (has_zone_id)
1012  
    if (has_zone_id)
995  
    {
1013  
    {
996  
        *dest++ = '%';
1014  
        *dest++ = '%';
997  
        *dest++ = '2';
1015  
        *dest++ = '2';
998  
        *dest++ = '5';
1016  
        *dest++ = '5';
999  
        dzn = detail::re_encode_unsafe(dest, dest + zn, zone_id, unreserved_chars);
1017  
        dzn = detail::re_encode_unsafe(dest, dest + zn, zone_id, unreserved_chars);
1000  
    }
1018  
    }
1001  
    *dest++ = ']';
1019  
    *dest++ = ']';
1002  
    // ipn + |"["| + |"]"| + (has_zone_id ? |"%"| + zn : 0)
1020  
    // ipn + |"["| + |"]"| + (has_zone_id ? |"%"| + zn : 0)
1003 -
    impl_.decoded_[id_host] = ipn + 2 + has_zone_id * (1 + dzn);
1021 +
    impl_.decoded_[id_host] = detail::to_size_type(
 
1022 +
        ipn + 2 + has_zone_id * (1 + dzn));
1004  
    impl_.host_type_ = urls::host_type::ipv6;
1023  
    impl_.host_type_ = urls::host_type::ipv6;
1005  
    auto bytes = addr.to_bytes();
1024  
    auto bytes = addr.to_bytes();
1006  
    std::memcpy(
1025  
    std::memcpy(
1007  
        impl_.ip_addr_,
1026  
        impl_.ip_addr_,
1008  
        bytes.data(),
1027  
        bytes.data(),
1009  
        bytes.size());
1028  
        bytes.size());
1010  
}
1029  
}
1011  

1030  

1012  
url_base&
1031  
url_base&
1013  
url_base::
1032  
url_base::
1014  
set_host_ipvfuture(
1033  
set_host_ipvfuture(
1015  
    core::string_view s)
1034  
    core::string_view s)
1016  
{
1035  
{
1017  
    op_t op(*this, &s);
1036  
    op_t op(*this, &s);
1018  
    // validate
1037  
    // validate
1019  
    grammar::parse(s,
1038  
    grammar::parse(s,
1020  
        detail::ipvfuture_rule
1039  
        detail::ipvfuture_rule
1021  
            ).value(BOOST_URL_POS);
1040  
            ).value(BOOST_URL_POS);
1022  
    auto dest = set_host_impl(
1041  
    auto dest = set_host_impl(
1023  
        s.size() + 2, op);
1042  
        s.size() + 2, op);
1024  
    *dest++ = '[';
1043  
    *dest++ = '[';
1025  
    dest += s.copy(dest, s.size());
1044  
    dest += s.copy(dest, s.size());
1026  
    *dest = ']';
1045  
    *dest = ']';
1027  
    impl_.host_type_ =
1046  
    impl_.host_type_ =
1028  
        urls::host_type::ipvfuture;
1047  
        urls::host_type::ipvfuture;
1029 -
    impl_.decoded_[id_host] = s.size() + 2;
1048 +
    impl_.decoded_[id_host] =
 
1049 +
        detail::to_size_type(s.size() + 2);
1030  
    return *this;
1050  
    return *this;
1031  
}
1051  
}
1032  

1052  

1033  
url_base&
1053  
url_base&
1034  
url_base::
1054  
url_base::
1035  
set_host_name(
1055  
set_host_name(
1036  
    core::string_view s)
1056  
    core::string_view s)
1037  
{
1057  
{
1038  
    bool is_ipv4 = false;
1058  
    bool is_ipv4 = false;
1039  
    if(s.size() >= 7) // "0.0.0.0"
1059  
    if(s.size() >= 7) // "0.0.0.0"
1040  
    {
1060  
    {
1041  
        // IPv4-address
1061  
        // IPv4-address
1042  
        if(parse_ipv4_address(s).has_value())
1062  
        if(parse_ipv4_address(s).has_value())
1043  
            is_ipv4 = true;
1063  
            is_ipv4 = true;
1044  
    }
1064  
    }
1045  
    auto allowed = detail::host_chars;
1065  
    auto allowed = detail::host_chars;
1046  
    if(is_ipv4)
1066  
    if(is_ipv4)
1047  
        allowed = allowed - '.';
1067  
        allowed = allowed - '.';
1048  

1068  

1049  
    op_t op(*this, &s);
1069  
    op_t op(*this, &s);
1050  
    encoding_opts opt;
1070  
    encoding_opts opt;
1051  
    auto const n = encoded_size(
1071  
    auto const n = encoded_size(
1052  
        s, allowed, opt);
1072  
        s, allowed, opt);
1053  
    auto dest = set_host_impl(n, op);
1073  
    auto dest = set_host_impl(n, op);
1054  
    encode_unsafe(
1074  
    encode_unsafe(
1055  
        dest,
1075  
        dest,
1056  
        n,
1076  
        n,
1057  
        s,
1077  
        s,
1058  
        allowed,
1078  
        allowed,
1059  
        opt);
1079  
        opt);
1060  
    impl_.host_type_ =
1080  
    impl_.host_type_ =
1061  
        urls::host_type::name;
1081  
        urls::host_type::name;
1062 -
    impl_.decoded_[id_host] = s.size();
1082 +
    impl_.decoded_[id_host] =
 
1083 +
        detail::to_size_type(s.size());
1063  
    return *this;
1084  
    return *this;
1064  
}
1085  
}
1065  

1086  

1066  
url_base&
1087  
url_base&
1067  
url_base::
1088  
url_base::
1068  
set_encoded_host_name(
1089  
set_encoded_host_name(
1069  
    pct_string_view s)
1090  
    pct_string_view s)
1070  
{
1091  
{
1071  
    bool is_ipv4 = false;
1092  
    bool is_ipv4 = false;
1072  
    if(s.size() >= 7) // "0.0.0.0"
1093  
    if(s.size() >= 7) // "0.0.0.0"
1073  
    {
1094  
    {
1074  
        // IPv4-address
1095  
        // IPv4-address
1075  
        if(parse_ipv4_address(s).has_value())
1096  
        if(parse_ipv4_address(s).has_value())
1076  
            is_ipv4 = true;
1097  
            is_ipv4 = true;
1077  
    }
1098  
    }
1078  
    auto allowed = detail::host_chars;
1099  
    auto allowed = detail::host_chars;
1079  
    if(is_ipv4)
1100  
    if(is_ipv4)
1080  
        allowed = allowed - '.';
1101  
        allowed = allowed - '.';
1081  

1102  

1082  
    op_t op(*this, &detail::ref(s));
1103  
    op_t op(*this, &detail::ref(s));
1083  
    auto const n = detail::re_encoded_size_unsafe(
1104  
    auto const n = detail::re_encoded_size_unsafe(
1084  
        s, allowed);
1105  
        s, allowed);
1085  
    auto dest = set_host_impl(n, op);
1106  
    auto dest = set_host_impl(n, op);
1086  
    impl_.decoded_[id_host] =
1107  
    impl_.decoded_[id_host] =
1087 -
        detail::re_encode_unsafe(
1108 +
        detail::to_size_type(detail::re_encode_unsafe(
1088  
            dest,
1109  
            dest,
1089  
            dest + n,
1110  
            dest + n,
1090  
            s,
1111  
            s,
1091 -
            allowed);
1112 +
            allowed));
1092  
    BOOST_ASSERT(
1113  
    BOOST_ASSERT(
1093  
        impl_.decoded_[id_host] ==
1114  
        impl_.decoded_[id_host] ==
1094  
            s.decoded_size());
1115  
            s.decoded_size());
1095  
    impl_.host_type_ =
1116  
    impl_.host_type_ =
1096  
        urls::host_type::name;
1117  
        urls::host_type::name;
1097  
    return *this;
1118  
    return *this;
1098  
}
1119  
}
1099  

1120  

1100  
//------------------------------------------------
1121  
//------------------------------------------------
1101  

1122  

1102  
url_base&
1123  
url_base&
1103  
url_base::
1124  
url_base::
1104  
set_port_number(
1125  
set_port_number(
1105  
    std::uint16_t n)
1126  
    std::uint16_t n)
1106  
{
1127  
{
1107  
    op_t op(*this);
1128  
    op_t op(*this);
1108  
    auto s =
1129  
    auto s =
1109  
        detail::make_printed(n);
1130  
        detail::make_printed(n);
1110  
    auto dest = set_port_impl(
1131  
    auto dest = set_port_impl(
1111  
        s.string().size(), op);
1132  
        s.string().size(), op);
1112  
    std::memcpy(
1133  
    std::memcpy(
1113  
        dest, s.string().data(),
1134  
        dest, s.string().data(),
1114  
            s.string().size());
1135  
            s.string().size());
1115  
    impl_.port_number_ = n;
1136  
    impl_.port_number_ = n;
1116  
    return *this;
1137  
    return *this;
1117  
}
1138  
}
1118  

1139  

1119  
url_base&
1140  
url_base&
1120  
url_base::
1141  
url_base::
1121  
set_port(
1142  
set_port(
1122  
    core::string_view s)
1143  
    core::string_view s)
1123  
{
1144  
{
1124  
    op_t op(*this, &s);
1145  
    op_t op(*this, &s);
1125  
    auto t = grammar::parse(s,
1146  
    auto t = grammar::parse(s,
1126  
        detail::port_rule{}
1147  
        detail::port_rule{}
1127  
            ).value(BOOST_URL_POS);
1148  
            ).value(BOOST_URL_POS);
1128  
    auto dest =
1149  
    auto dest =
1129  
        set_port_impl(t.str.size(), op);
1150  
        set_port_impl(t.str.size(), op);
1130  
    std::memcpy(dest,
1151  
    std::memcpy(dest,
1131  
        t.str.data(), t.str.size());
1152  
        t.str.data(), t.str.size());
1132  
    if(t.has_number)
1153  
    if(t.has_number)
1133  
        impl_.port_number_ = t.number;
1154  
        impl_.port_number_ = t.number;
1134  
    else
1155  
    else
1135  
        impl_.port_number_ = 0;
1156  
        impl_.port_number_ = 0;
1136  
    return *this;
1157  
    return *this;
1137  
}
1158  
}
1138  

1159  

1139  
url_base&
1160  
url_base&
1140  
url_base::
1161  
url_base::
1141  
remove_port() noexcept
1162  
remove_port() noexcept
1142  
{
1163  
{
1143  
    op_t op(*this);
1164  
    op_t op(*this);
1144  
    resize_impl(id_port, 0, op);
1165  
    resize_impl(id_port, 0, op);
1145  
    impl_.port_number_ = 0;
1166  
    impl_.port_number_ = 0;
1146  
    return *this;
1167  
    return *this;
1147  
}
1168  
}
1148  

1169  

1149  
//------------------------------------------------
1170  
//------------------------------------------------
1150  
//
1171  
//
1151  
// Compound Fields
1172  
// Compound Fields
1152  
//
1173  
//
1153  
//------------------------------------------------
1174  
//------------------------------------------------
1154  

1175  

1155  
url_base&
1176  
url_base&
1156  
url_base::
1177  
url_base::
1157  
remove_origin()
1178  
remove_origin()
1158  
{
1179  
{
1159  
    // these two calls perform 2 memmoves instead of 1
1180  
    // these two calls perform 2 memmoves instead of 1
1160  
    remove_authority();
1181  
    remove_authority();
1161  
    remove_scheme();
1182  
    remove_scheme();
1162  
    return *this;
1183  
    return *this;
1163  
}
1184  
}
1164  

1185  

1165  
//------------------------------------------------
1186  
//------------------------------------------------
1166  
//
1187  
//
1167  
// Path
1188  
// Path
1168  
//
1189  
//
1169  
//------------------------------------------------
1190  
//------------------------------------------------
1170  

1191  

1171  
bool
1192  
bool
1172  
url_base::
1193  
url_base::
1173  
set_path_absolute(
1194  
set_path_absolute(
1174  
    bool absolute)
1195  
    bool absolute)
1175  
{
1196  
{
1176  
    op_t op(*this);
1197  
    op_t op(*this);
1177  

1198  

1178  
    // check if path empty
1199  
    // check if path empty
1179  
    if(impl_.len(id_path) == 0)
1200  
    if(impl_.len(id_path) == 0)
1180  
    {
1201  
    {
1181  
        if(! absolute)
1202  
        if(! absolute)
1182  
        {
1203  
        {
1183  
            // already not absolute
1204  
            // already not absolute
1184  
            return true;
1205  
            return true;
1185  
        }
1206  
        }
1186  

1207  

1187  
        // add '/'
1208  
        // add '/'
1188  
        auto dest = resize_impl(
1209  
        auto dest = resize_impl(
1189  
            id_path, 1, op);
1210  
            id_path, 1, op);
1190  
        *dest = '/';
1211  
        *dest = '/';
1191  
        ++impl_.decoded_[id_path];
1212  
        ++impl_.decoded_[id_path];
1192  
        return true;
1213  
        return true;
1193  
    }
1214  
    }
1194  

1215  

1195  
    // check if path absolute
1216  
    // check if path absolute
1196  
    if(s_[impl_.offset(id_path)] == '/')
1217  
    if(s_[impl_.offset(id_path)] == '/')
1197  
    {
1218  
    {
1198  
        if(absolute)
1219  
        if(absolute)
1199  
        {
1220  
        {
1200  
            // already absolute
1221  
            // already absolute
1201  
            return true;
1222  
            return true;
1202  
        }
1223  
        }
1203  

1224  

1204  
        if( has_authority() &&
1225  
        if( has_authority() &&
1205  
            impl_.len(id_path) > 1)
1226  
            impl_.len(id_path) > 1)
1206  
        {
1227  
        {
1207  
            // can't do it, paths are always
1228  
            // can't do it, paths are always
1208  
            // absolute when authority present!
1229  
            // absolute when authority present!
1209  
            return false;
1230  
            return false;
1210  
        }
1231  
        }
1211  

1232  

1212  
        auto p = encoded_path();
1233  
        auto p = encoded_path();
1213  
        auto pos = p.find_first_of(":/", 1);
1234  
        auto pos = p.find_first_of(":/", 1);
1214  
        if (pos != core::string_view::npos &&
1235  
        if (pos != core::string_view::npos &&
1215  
            p[pos] == ':')
1236  
            p[pos] == ':')
1216  
        {
1237  
        {
1217  
            // prepend with .
1238  
            // prepend with .
1218  
            auto n = impl_.len(id_path);
1239  
            auto n = impl_.len(id_path);
1219  
            resize_impl(id_path, n + 1, op);
1240  
            resize_impl(id_path, n + 1, op);
1220  
            std::memmove(
1241  
            std::memmove(
1221  
                s_ + impl_.offset(id_path) + 1,
1242  
                s_ + impl_.offset(id_path) + 1,
1222  
                s_ + impl_.offset(id_path), n);
1243  
                s_ + impl_.offset(id_path), n);
1223  
            *(s_ + impl_.offset(id_path)) = '.';
1244  
            *(s_ + impl_.offset(id_path)) = '.';
1224  
            ++impl_.decoded_[id_path];
1245  
            ++impl_.decoded_[id_path];
1225  
            return true;
1246  
            return true;
1226  
        }
1247  
        }
1227  

1248  

1228  
        // remove '/'
1249  
        // remove '/'
1229  
        auto n = impl_.len(id_port);
1250  
        auto n = impl_.len(id_port);
1230  
        impl_.split(id_port, n + 1);
1251  
        impl_.split(id_port, n + 1);
1231  
        resize_impl(id_port, n, op);
1252  
        resize_impl(id_port, n, op);
1232  
        --impl_.decoded_[id_path];
1253  
        --impl_.decoded_[id_path];
1233  
        return true;
1254  
        return true;
1234  
    }
1255  
    }
1235  

1256  

1236  
    if(! absolute)
1257  
    if(! absolute)
1237  
    {
1258  
    {
1238  
        // already not absolute
1259  
        // already not absolute
1239  
        return true;
1260  
        return true;
1240  
    }
1261  
    }
1241  

1262  

1242  
    // add '/'
1263  
    // add '/'
1243  
    auto n = impl_.len(id_port);
1264  
    auto n = impl_.len(id_port);
1244  
    auto dest = resize_impl(
1265  
    auto dest = resize_impl(
1245  
        id_port, n + 1, op) + n;
1266  
        id_port, n + 1, op) + n;
1246  
    impl_.split(id_port, n);
1267  
    impl_.split(id_port, n);
1247  
    *dest = '/';
1268  
    *dest = '/';
1248  
    ++impl_.decoded_[id_path];
1269  
    ++impl_.decoded_[id_path];
1249  
    return true;
1270  
    return true;
1250  
}
1271  
}
1251  

1272  

1252  
url_base&
1273  
url_base&
1253  
url_base::
1274  
url_base::
1254  
set_path(
1275  
set_path(
1255  
    core::string_view s)
1276  
    core::string_view s)
1256  
{
1277  
{
1257  
    op_t op(*this, &s);
1278  
    op_t op(*this, &s);
1258  
    encoding_opts opt;
1279  
    encoding_opts opt;
1259  

1280  

1260  
//------------------------------------------------
1281  
//------------------------------------------------
1261  
//
1282  
//
1262  
//  Calculate encoded size
1283  
//  Calculate encoded size
1263  
//
1284  
//
1264  
// - "/"s are not encoded
1285  
// - "/"s are not encoded
1265  
// - "%2F"s are not encoded
1286  
// - "%2F"s are not encoded
1266  
//
1287  
//
1267  
// - reserved path chars are re-encoded
1288  
// - reserved path chars are re-encoded
1268  
// - colons in first segment might need to be re-encoded
1289  
// - colons in first segment might need to be re-encoded
1269  
// - the path might need to receive a prefix
1290  
// - the path might need to receive a prefix
1270  
    auto const n = encoded_size(
1291  
    auto const n = encoded_size(
1271  
        s, detail::path_chars, opt);
1292  
        s, detail::path_chars, opt);
1272  
    std::size_t n_reencode_colons = 0;
1293  
    std::size_t n_reencode_colons = 0;
1273  
    core::string_view first_seg;
1294  
    core::string_view first_seg;
1274  
    if (!has_scheme() &&
1295  
    if (!has_scheme() &&
1275  
        !has_authority() &&
1296  
        !has_authority() &&
1276  
        !s.starts_with('/'))
1297  
        !s.starts_with('/'))
1277  
    {
1298  
    {
1278  
        // the first segment with unencoded colons would look
1299  
        // the first segment with unencoded colons would look
1279  
        // like the scheme
1300  
        // like the scheme
1280  
        first_seg = detail::to_sv(s);
1301  
        first_seg = detail::to_sv(s);
1281  
        std::size_t p = s.find('/');
1302  
        std::size_t p = s.find('/');
1282  
        if (p != core::string_view::npos)
1303  
        if (p != core::string_view::npos)
1283  
            first_seg = s.substr(0, p);
1304  
            first_seg = s.substr(0, p);
1284  
        n_reencode_colons = std::count(
1305  
        n_reencode_colons = std::count(
1285  
            first_seg.begin(), first_seg.end(), ':');
1306  
            first_seg.begin(), first_seg.end(), ':');
1286  
    }
1307  
    }
1287  
    // the authority can only be followed by an empty or relative path
1308  
    // the authority can only be followed by an empty or relative path
1288  
    // if we have an authority and the path is a non-empty relative path, we
1309  
    // if we have an authority and the path is a non-empty relative path, we
1289  
    // add the "/" prefix to make it valid.
1310  
    // add the "/" prefix to make it valid.
1290  
    bool make_absolute =
1311  
    bool make_absolute =
1291  
        has_authority() &&
1312  
        has_authority() &&
1292  
        !s.starts_with('/') &&
1313  
        !s.starts_with('/') &&
1293  
        !s.empty();
1314  
        !s.empty();
1294  
    // a path starting with "//" might look like the authority.
1315  
    // a path starting with "//" might look like the authority.
1295  
    // we add a "/." prefix to prevent that
1316  
    // we add a "/." prefix to prevent that
1296  
    bool add_dot_segment =
1317  
    bool add_dot_segment =
1297  
        !make_absolute &&
1318  
        !make_absolute &&
1298  
        s.starts_with("//");
1319  
        s.starts_with("//");
1299  

1320  

1300  
//------------------------------------------------
1321  
//------------------------------------------------
1301  
//
1322  
//
1302  
//  Re-encode data
1323  
//  Re-encode data
1303  
//
1324  
//
1304  
    auto dest = set_path_impl(
1325  
    auto dest = set_path_impl(
1305  
        n + make_absolute + 2 * n_reencode_colons + 2 * add_dot_segment, op);
1326  
        n + make_absolute + 2 * n_reencode_colons + 2 * add_dot_segment, op);
1306  
    impl_.decoded_[id_path] = 0;
1327  
    impl_.decoded_[id_path] = 0;
1307  
    if (!dest)
1328  
    if (!dest)
1308  
    {
1329  
    {
1309  
        impl_.nseg_ = 0;
1330  
        impl_.nseg_ = 0;
1310  
        return *this;
1331  
        return *this;
1311  
    }
1332  
    }
1312  
    if (make_absolute)
1333  
    if (make_absolute)
1313  
    {
1334  
    {
1314  
        *dest++ = '/';
1335  
        *dest++ = '/';
1315  
        impl_.decoded_[id_path] += 1;
1336  
        impl_.decoded_[id_path] += 1;
1316  
    }
1337  
    }
1317  
    else if (add_dot_segment)
1338  
    else if (add_dot_segment)
1318  
    {
1339  
    {
1319  
        *dest++ = '/';
1340  
        *dest++ = '/';
1320  
        *dest++ = '.';
1341  
        *dest++ = '.';
1321  
        impl_.decoded_[id_path] += 2;
1342  
        impl_.decoded_[id_path] += 2;
1322  
    }
1343  
    }
1323  
    dest += encode_unsafe(
1344  
    dest += encode_unsafe(
1324  
        dest,
1345  
        dest,
1325  
        impl_.get(id_query).data() - dest,
1346  
        impl_.get(id_query).data() - dest,
1326  
        first_seg,
1347  
        first_seg,
1327  
        detail::segment_chars - ':',
1348  
        detail::segment_chars - ':',
1328  
        opt);
1349  
        opt);
1329  
    dest += encode_unsafe(
1350  
    dest += encode_unsafe(
1330  
        dest,
1351  
        dest,
1331  
        impl_.get(id_query).data() - dest,
1352  
        impl_.get(id_query).data() - dest,
1332  
        s.substr(first_seg.size()),
1353  
        s.substr(first_seg.size()),
1333  
        detail::path_chars,
1354  
        detail::path_chars,
1334  
        opt);
1355  
        opt);
1335 -
    impl_.decoded_[id_path] += s.size();
1356 +
    impl_.decoded_[id_path] +=
 
1357 +
        detail::to_size_type(s.size());
1336  
    BOOST_ASSERT(!dest || dest == impl_.get(id_query).data());
1358  
    BOOST_ASSERT(!dest || dest == impl_.get(id_query).data());
1337  
    BOOST_ASSERT(
1359  
    BOOST_ASSERT(
1338  
        impl_.decoded_[id_path] ==
1360  
        impl_.decoded_[id_path] ==
1339  
        s.size() + make_absolute + 2 * add_dot_segment);
1361  
        s.size() + make_absolute + 2 * add_dot_segment);
1340  

1362  

1341  
//------------------------------------------------
1363  
//------------------------------------------------
1342  
//
1364  
//
1343  
//  Update path parameters
1365  
//  Update path parameters
1344  
//
1366  
//
1345  
    // get the encoded_path with the replacements we applied
1367  
    // get the encoded_path with the replacements we applied
1346  
    if (s == "/")
1368  
    if (s == "/")
1347  
    {
1369  
    {
1348  
        // "/" maps to sequence {}
1370  
        // "/" maps to sequence {}
1349  
        impl_.nseg_ = 0;
1371  
        impl_.nseg_ = 0;
1350  
    }
1372  
    }
1351  
    else if (!s.empty())
1373  
    else if (!s.empty())
1352  
    {
1374  
    {
1353  
        if (s.starts_with("/./"))
1375  
        if (s.starts_with("/./"))
1354  
            s = s.substr(2);
1376  
            s = s.substr(2);
1355  
        // count segments as number of '/'s + 1
1377  
        // count segments as number of '/'s + 1
1356 -
        impl_.nseg_ = std::count(
1378 +
        impl_.nseg_ = detail::to_size_type(
1357 -
            s.begin() + 1, s.end(), '/') + 1;
1379 +
            std::count(
 
1380 +
                s.begin() + 1, s.end(), '/') + 1);
1358  
    }
1381  
    }
1359  
    else
1382  
    else
1360  
    {
1383  
    {
1361  
        // an empty relative path maps to sequence {}
1384  
        // an empty relative path maps to sequence {}
1362  
        impl_.nseg_ = 0;
1385  
        impl_.nseg_ = 0;
1363  
    }
1386  
    }
1364  

1387  

1365  
    check_invariants();
1388  
    check_invariants();
1366  
    return *this;
1389  
    return *this;
1367  
}
1390  
}
1368  

1391  

1369  
url_base&
1392  
url_base&
1370  
url_base::
1393  
url_base::
1371  
set_encoded_path(
1394  
set_encoded_path(
1372  
    pct_string_view s)
1395  
    pct_string_view s)
1373  
{
1396  
{
1374  
    op_t op(*this, &detail::ref(s));
1397  
    op_t op(*this, &detail::ref(s));
1375  

1398  

1376  
//------------------------------------------------
1399  
//------------------------------------------------
1377  
//
1400  
//
1378  
//  Calculate re-encoded output size
1401  
//  Calculate re-encoded output size
1379  
//
1402  
//
1380  
// - reserved path chars are re-encoded
1403  
// - reserved path chars are re-encoded
1381  
// - colons in first segment might need to be re-encoded
1404  
// - colons in first segment might need to be re-encoded
1382  
// - the path might need to receive a prefix
1405  
// - the path might need to receive a prefix
1383  
    auto const n = detail::re_encoded_size_unsafe(
1406  
    auto const n = detail::re_encoded_size_unsafe(
1384  
        s, detail::path_chars);
1407  
        s, detail::path_chars);
1385  
    std::size_t n_reencode_colons = 0;
1408  
    std::size_t n_reencode_colons = 0;
1386  
    core::string_view first_seg;
1409  
    core::string_view first_seg;
1387  
    if (!has_scheme() &&
1410  
    if (!has_scheme() &&
1388  
        !has_authority() &&
1411  
        !has_authority() &&
1389  
        !s.starts_with('/'))
1412  
        !s.starts_with('/'))
1390  
    {
1413  
    {
1391  
        // the first segment with unencoded colons would look
1414  
        // the first segment with unencoded colons would look
1392  
        // like the scheme
1415  
        // like the scheme
1393  
        first_seg = detail::to_sv(s);
1416  
        first_seg = detail::to_sv(s);
1394  
        std::size_t p = s.find('/');
1417  
        std::size_t p = s.find('/');
1395  
        if (p != core::string_view::npos)
1418  
        if (p != core::string_view::npos)
1396  
            first_seg = s.substr(0, p);
1419  
            first_seg = s.substr(0, p);
1397  
        n_reencode_colons = std::count(
1420  
        n_reencode_colons = std::count(
1398  
            first_seg.begin(), first_seg.end(), ':');
1421  
            first_seg.begin(), first_seg.end(), ':');
1399  
    }
1422  
    }
1400  
    // the authority can only be followed by an empty or relative path
1423  
    // the authority can only be followed by an empty or relative path
1401  
    // if we have an authority and the path is a non-empty relative path, we
1424  
    // if we have an authority and the path is a non-empty relative path, we
1402  
    // add the "/" prefix to make it valid.
1425  
    // add the "/" prefix to make it valid.
1403  
    bool make_absolute =
1426  
    bool make_absolute =
1404  
        has_authority() &&
1427  
        has_authority() &&
1405  
        !s.starts_with('/') &&
1428  
        !s.starts_with('/') &&
1406  
        !s.empty();
1429  
        !s.empty();
1407  
    // a path starting with "//" might look like the authority
1430  
    // a path starting with "//" might look like the authority
1408  
    // we add a "/." prefix to prevent that
1431  
    // we add a "/." prefix to prevent that
1409  
    bool add_dot_segment =
1432  
    bool add_dot_segment =
1410  
        !make_absolute &&
1433  
        !make_absolute &&
1411  
        !has_authority() &&
1434  
        !has_authority() &&
1412  
        s.starts_with("//");
1435  
        s.starts_with("//");
1413  

1436  

1414  
//------------------------------------------------
1437  
//------------------------------------------------
1415  
//
1438  
//
1416  
//  Re-encode data
1439  
//  Re-encode data
1417  
//
1440  
//
1418  
    auto dest = set_path_impl(
1441  
    auto dest = set_path_impl(
1419  
        n + make_absolute + 2 * n_reencode_colons + 2 * add_dot_segment, op);
1442  
        n + make_absolute + 2 * n_reencode_colons + 2 * add_dot_segment, op);
1420  
    impl_.decoded_[id_path] = 0;
1443  
    impl_.decoded_[id_path] = 0;
1421  
    if (!dest)
1444  
    if (!dest)
1422  
    {
1445  
    {
1423  
        impl_.nseg_ = 0;
1446  
        impl_.nseg_ = 0;
1424  
        return *this;
1447  
        return *this;
1425  
    }
1448  
    }
1426  
    if (make_absolute)
1449  
    if (make_absolute)
1427  
    {
1450  
    {
1428  
        *dest++ = '/';
1451  
        *dest++ = '/';
1429  
        impl_.decoded_[id_path] += 1;
1452  
        impl_.decoded_[id_path] += 1;
1430  
    }
1453  
    }
1431  
    else if (add_dot_segment)
1454  
    else if (add_dot_segment)
1432  
    {
1455  
    {
1433  
        *dest++ = '/';
1456  
        *dest++ = '/';
1434  
        *dest++ = '.';
1457  
        *dest++ = '.';
1435  
        impl_.decoded_[id_path] += 2;
1458  
        impl_.decoded_[id_path] += 2;
1436  
    }
1459  
    }
1437  
    impl_.decoded_[id_path] +=
1460  
    impl_.decoded_[id_path] +=
1438 -
        detail::re_encode_unsafe(
1461 +
        detail::to_size_type(detail::re_encode_unsafe(
1439  
            dest,
1462  
            dest,
1440  
            impl_.get(id_query).data(),
1463  
            impl_.get(id_query).data(),
1441  
            first_seg,
1464  
            first_seg,
1442 -
            detail::segment_chars - ':');
1465 +
            detail::segment_chars - ':'));
1443  
    impl_.decoded_[id_path] +=
1466  
    impl_.decoded_[id_path] +=
1444 -
        detail::re_encode_unsafe(
1467 +
        detail::to_size_type(detail::re_encode_unsafe(
1445  
            dest,
1468  
            dest,
1446  
            impl_.get(id_query).data(),
1469  
            impl_.get(id_query).data(),
1447  
            s.substr(first_seg.size()),
1470  
            s.substr(first_seg.size()),
1448 -
            detail::path_chars);
1471 +
            detail::path_chars));
1449  
    BOOST_ASSERT(dest == impl_.get(id_query).data());
1472  
    BOOST_ASSERT(dest == impl_.get(id_query).data());
1450  
    BOOST_ASSERT(
1473  
    BOOST_ASSERT(
1451  
        impl_.decoded_[id_path] ==
1474  
        impl_.decoded_[id_path] ==
1452  
        s.decoded_size() + make_absolute + 2 * add_dot_segment);
1475  
        s.decoded_size() + make_absolute + 2 * add_dot_segment);
1453  

1476  

1454  
//------------------------------------------------
1477  
//------------------------------------------------
1455  
//
1478  
//
1456  
//  Update path parameters
1479  
//  Update path parameters
1457  
//
1480  
//
1458  
    // get the encoded_path with the replacements we applied
1481  
    // get the encoded_path with the replacements we applied
1459  
    if (s == "/")
1482  
    if (s == "/")
1460  
    {
1483  
    {
1461  
        // "/" maps to sequence {}
1484  
        // "/" maps to sequence {}
1462  
        impl_.nseg_ = 0;
1485  
        impl_.nseg_ = 0;
1463  
    }
1486  
    }
1464  
    else if (!s.empty())
1487  
    else if (!s.empty())
1465  
    {
1488  
    {
1466  
        if (s.starts_with("/./"))
1489  
        if (s.starts_with("/./"))
1467  
            s = s.substr(2);
1490  
            s = s.substr(2);
1468  
        // count segments as number of '/'s + 1
1491  
        // count segments as number of '/'s + 1
1469 -
        impl_.nseg_ = std::count(
1492 +
        impl_.nseg_ = detail::to_size_type(
1470 -
            s.begin() + 1, s.end(), '/') + 1;
1493 +
            std::count(
 
1494 +
                s.begin() + 1, s.end(), '/') + 1);
1471  
    }
1495  
    }
1472  
    else
1496  
    else
1473  
    {
1497  
    {
1474  
        // an empty relative path maps to sequence {}
1498  
        // an empty relative path maps to sequence {}
1475  
        impl_.nseg_ = 0;
1499  
        impl_.nseg_ = 0;
1476  
    }
1500  
    }
1477  

1501  

1478  
    check_invariants();
1502  
    check_invariants();
1479  
    return *this;
1503  
    return *this;
1480  
}
1504  
}
1481  

1505  

1482  
segments_ref
1506  
segments_ref
1483  
url_base::
1507  
url_base::
1484  
segments() noexcept
1508  
segments() noexcept
1485  
{
1509  
{
1486  
    return {*this};
1510  
    return {*this};
1487  
}
1511  
}
1488  

1512  

1489  
segments_encoded_ref
1513  
segments_encoded_ref
1490  
url_base::
1514  
url_base::
1491  
encoded_segments() noexcept
1515  
encoded_segments() noexcept
1492  
{
1516  
{
1493  
    return {*this};
1517  
    return {*this};
1494  
}
1518  
}
1495  

1519  

1496  
//------------------------------------------------
1520  
//------------------------------------------------
1497  
//
1521  
//
1498  
// Query
1522  
// Query
1499  
//
1523  
//
1500  
//------------------------------------------------
1524  
//------------------------------------------------
1501  

1525  

1502  
url_base&
1526  
url_base&
1503  
url_base::
1527  
url_base::
1504  
set_query(
1528  
set_query(
1505  
    core::string_view s)
1529  
    core::string_view s)
1506  
{
1530  
{
1507  
    edit_params(
1531  
    edit_params(
1508  
        detail::params_iter_impl(impl_),
1532  
        detail::params_iter_impl(impl_),
1509  
        detail::params_iter_impl(impl_, 0),
1533  
        detail::params_iter_impl(impl_, 0),
1510  
        detail::query_string_iter(s, true));
1534  
        detail::query_string_iter(s, true));
1511  
    return *this;
1535  
    return *this;
1512  
}
1536  
}
1513  

1537  

1514  
url_base&
1538  
url_base&
1515  
url_base::
1539  
url_base::
1516  
set_encoded_query(
1540  
set_encoded_query(
1517  
    pct_string_view s)
1541  
    pct_string_view s)
1518  
{
1542  
{
1519  
    op_t op(*this);
1543  
    op_t op(*this);
1520  
    std::size_t n = 0;      // encoded size
1544  
    std::size_t n = 0;      // encoded size
1521  
    std::size_t nparam = 1; // param count
1545  
    std::size_t nparam = 1; // param count
1522  
    auto const end = s.end();
1546  
    auto const end = s.end();
1523  
    auto p = s.begin();
1547  
    auto p = s.begin();
1524  

1548  

1525  
    // measure
1549  
    // measure
1526  
    while(p != end)
1550  
    while(p != end)
1527  
    {
1551  
    {
1528  
        if(*p == '&')
1552  
        if(*p == '&')
1529  
        {
1553  
        {
1530  
            ++p;
1554  
            ++p;
1531  
            ++n;
1555  
            ++n;
1532  
            ++nparam;
1556  
            ++nparam;
1533  
        }
1557  
        }
1534  
        else if(*p != '%')
1558  
        else if(*p != '%')
1535  
        {
1559  
        {
1536  
            if(detail::query_chars(*p))
1560  
            if(detail::query_chars(*p))
1537  
                n += 1; // allowed
1561  
                n += 1; // allowed
1538  
            else
1562  
            else
1539  
                n += 3; // escaped
1563  
                n += 3; // escaped
1540  
            ++p;
1564  
            ++p;
1541  
        }
1565  
        }
1542  
        else
1566  
        else
1543  
        {
1567  
        {
1544  
            // escape
1568  
            // escape
1545  
            n += 3;
1569  
            n += 3;
1546  
            p += 3;
1570  
            p += 3;
1547  
        }
1571  
        }
1548  
    }
1572  
    }
1549  

1573  

1550  
    // resize
1574  
    // resize
1551  
    auto dest = resize_impl(
1575  
    auto dest = resize_impl(
1552  
        id_query, n + 1, op);
1576  
        id_query, n + 1, op);
1553  
    *dest++ = '?';
1577  
    *dest++ = '?';
1554  

1578  

1555  
    // encode
1579  
    // encode
1556  
    impl_.decoded_[id_query] =
1580  
    impl_.decoded_[id_query] =
1557 -
        detail::re_encode_unsafe(
1581 +
        detail::to_size_type(detail::re_encode_unsafe(
1558  
            dest,
1582  
            dest,
1559  
            dest + n,
1583  
            dest + n,
1560  
            s,
1584  
            s,
1561 -
            detail::query_chars);
1585 +
            detail::query_chars));
1562  
    BOOST_ASSERT(
1586  
    BOOST_ASSERT(
1563  
        impl_.decoded_[id_query] ==
1587  
        impl_.decoded_[id_query] ==
1564  
            s.decoded_size());
1588  
            s.decoded_size());
1565 -
    impl_.nparam_ = nparam;
1589 +
    impl_.nparam_ =
 
1590 +
        detail::to_size_type(nparam);
1566  
    return *this;
1591  
    return *this;
1567  
}
1592  
}
1568  

1593  

1569  
params_ref
1594  
params_ref
1570  
url_base::
1595  
url_base::
1571  
params() noexcept
1596  
params() noexcept
1572  
{
1597  
{
1573  
    return params_ref(
1598  
    return params_ref(
1574  
        *this,
1599  
        *this,
1575  
        encoding_opts{
1600  
        encoding_opts{
1576  
            true, false, false});
1601  
            true, false, false});
1577  
}
1602  
}
1578  

1603  

1579  
params_ref
1604  
params_ref
1580  
url_base::
1605  
url_base::
1581  
params(encoding_opts opt) noexcept
1606  
params(encoding_opts opt) noexcept
1582  
{
1607  
{
1583  
    return {*this, opt};
1608  
    return {*this, opt};
1584  
}
1609  
}
1585  

1610  

1586  
params_encoded_ref
1611  
params_encoded_ref
1587  
url_base::
1612  
url_base::
1588  
encoded_params() noexcept
1613  
encoded_params() noexcept
1589  
{
1614  
{
1590  
    return {*this};
1615  
    return {*this};
1591  
}
1616  
}
1592  

1617  

1593  
url_base&
1618  
url_base&
1594  
url_base::
1619  
url_base::
1595  
set_params(
1620  
set_params(
1596  
    std::initializer_list<param_view> ps,
1621  
    std::initializer_list<param_view> ps,
1597  
    encoding_opts opts) noexcept
1622  
    encoding_opts opts) noexcept
1598  
{
1623  
{
1599  
    params(opts).assign(ps);
1624  
    params(opts).assign(ps);
1600  
    return *this;
1625  
    return *this;
1601  
}
1626  
}
1602  

1627  

1603  
url_base&
1628  
url_base&
1604  
url_base::
1629  
url_base::
1605  
set_encoded_params( std::initializer_list< param_pct_view > ps ) noexcept
1630  
set_encoded_params( std::initializer_list< param_pct_view > ps ) noexcept
1606  
{
1631  
{
1607  
    encoded_params().assign(ps);
1632  
    encoded_params().assign(ps);
1608  
    return *this;
1633  
    return *this;
1609  
}
1634  
}
1610  

1635  

1611  
url_base&
1636  
url_base&
1612  
url_base::
1637  
url_base::
1613  
remove_query() noexcept
1638  
remove_query() noexcept
1614  
{
1639  
{
1615  
    op_t op(*this);
1640  
    op_t op(*this);
1616  
    resize_impl(id_query, 0, op);
1641  
    resize_impl(id_query, 0, op);
1617  
    impl_.nparam_ = 0;
1642  
    impl_.nparam_ = 0;
1618  
    impl_.decoded_[id_query] = 0;
1643  
    impl_.decoded_[id_query] = 0;
1619  
    return *this;
1644  
    return *this;
1620  
}
1645  
}
1621  

1646  

1622  
//------------------------------------------------
1647  
//------------------------------------------------
1623  
//
1648  
//
1624  
// Fragment
1649  
// Fragment
1625  
//
1650  
//
1626  
//------------------------------------------------
1651  
//------------------------------------------------
1627  

1652  

1628  
url_base&
1653  
url_base&
1629  
url_base::
1654  
url_base::
1630  
remove_fragment() noexcept
1655  
remove_fragment() noexcept
1631  
{
1656  
{
1632  
    op_t op(*this);
1657  
    op_t op(*this);
1633  
    resize_impl(id_frag, 0, op);
1658  
    resize_impl(id_frag, 0, op);
1634  
    impl_.decoded_[id_frag] = 0;
1659  
    impl_.decoded_[id_frag] = 0;
1635  
    return *this;
1660  
    return *this;
1636  
}
1661  
}
1637  

1662  

1638  
url_base&
1663  
url_base&
1639  
url_base::
1664  
url_base::
1640  
set_fragment(core::string_view s)
1665  
set_fragment(core::string_view s)
1641  
{
1666  
{
1642  
    op_t op(*this, &s);
1667  
    op_t op(*this, &s);
1643  
    encoding_opts opt;
1668  
    encoding_opts opt;
1644  
    auto const n = encoded_size(
1669  
    auto const n = encoded_size(
1645  
        s,
1670  
        s,
1646  
        detail::fragment_chars,
1671  
        detail::fragment_chars,
1647  
        opt);
1672  
        opt);
1648  
    auto dest = resize_impl(
1673  
    auto dest = resize_impl(
1649  
        id_frag, n + 1, op);
1674  
        id_frag, n + 1, op);
1650  
    *dest++ = '#';
1675  
    *dest++ = '#';
1651  
    encode_unsafe(
1676  
    encode_unsafe(
1652  
        dest,
1677  
        dest,
1653  
        n,
1678  
        n,
1654  
        s,
1679  
        s,
1655  
        detail::fragment_chars,
1680  
        detail::fragment_chars,
1656  
        opt);
1681  
        opt);
1657 -
    impl_.decoded_[id_frag] = s.size();
1682 +
    impl_.decoded_[id_frag] =
 
1683 +
        detail::to_size_type(s.size());
1658  
    return *this;
1684  
    return *this;
1659  
}
1685  
}
1660  

1686  

1661  
url_base&
1687  
url_base&
1662  
url_base::
1688  
url_base::
1663  
set_encoded_fragment(
1689  
set_encoded_fragment(
1664  
    pct_string_view s)
1690  
    pct_string_view s)
1665  
{
1691  
{
1666  
    op_t op(*this, &detail::ref(s));
1692  
    op_t op(*this, &detail::ref(s));
1667  
    auto const n =
1693  
    auto const n =
1668  
        detail::re_encoded_size_unsafe(
1694  
        detail::re_encoded_size_unsafe(
1669  
            s,
1695  
            s,
1670  
            detail::fragment_chars);
1696  
            detail::fragment_chars);
1671  
    auto dest = resize_impl(
1697  
    auto dest = resize_impl(
1672  
        id_frag, n + 1, op);
1698  
        id_frag, n + 1, op);
1673  
    *dest++ = '#';
1699  
    *dest++ = '#';
1674  
    impl_.decoded_[id_frag] =
1700  
    impl_.decoded_[id_frag] =
1675 -
        detail::re_encode_unsafe(
1701 +
        detail::to_size_type(detail::re_encode_unsafe(
1676  
            dest,
1702  
            dest,
1677  
            dest + n,
1703  
            dest + n,
1678  
            s,
1704  
            s,
1679 -
            detail::fragment_chars);
1705 +
            detail::fragment_chars));
1680  
    BOOST_ASSERT(
1706  
    BOOST_ASSERT(
1681  
        impl_.decoded_[id_frag] ==
1707  
        impl_.decoded_[id_frag] ==
1682  
            s.decoded_size());
1708  
            s.decoded_size());
1683  
    return *this;
1709  
    return *this;
1684  
}
1710  
}
1685  

1711  

1686  
//------------------------------------------------
1712  
//------------------------------------------------
1687  
//
1713  
//
1688  
// Resolution
1714  
// Resolution
1689  
//
1715  
//
1690  
//------------------------------------------------
1716  
//------------------------------------------------
1691  

1717  

1692  
system::result<void>
1718  
system::result<void>
1693  
url_base::
1719  
url_base::
1694  
resolve(
1720  
resolve(
1695  
    url_view_base const& ref)
1721  
    url_view_base const& ref)
1696  
{
1722  
{
1697  
    if (this == &ref &&
1723  
    if (this == &ref &&
1698  
        has_scheme())
1724  
        has_scheme())
1699  
    {
1725  
    {
1700  
        normalize_path();
1726  
        normalize_path();
1701  
        return {};
1727  
        return {};
1702  
    }
1728  
    }
1703  

1729  

1704  
    if(! has_scheme())
1730  
    if(! has_scheme())
1705  
    {
1731  
    {
1706  
        BOOST_URL_RETURN_EC(error::not_a_base);
1732  
        BOOST_URL_RETURN_EC(error::not_a_base);
1707  
    }
1733  
    }
1708  

1734  

1709  
    op_t op(*this);
1735  
    op_t op(*this);
1710  

1736  

1711  
    //
1737  
    //
1712  
    // 5.2.2. Transform References
1738  
    // 5.2.2. Transform References
1713  
    // https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.2
1739  
    // https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.2
1714  
    //
1740  
    //
1715  

1741  

1716  
    if( ref.has_scheme() &&
1742  
    if( ref.has_scheme() &&
1717  
        ref.scheme() != scheme())
1743  
        ref.scheme() != scheme())
1718  
    {
1744  
    {
1719  
        reserve_impl(ref.size(), op);
1745  
        reserve_impl(ref.size(), op);
1720  
        copy(ref);
1746  
        copy(ref);
1721  
        normalize_path();
1747  
        normalize_path();
1722  
        return {};
1748  
        return {};
1723  
    }
1749  
    }
1724  
    if(ref.has_authority())
1750  
    if(ref.has_authority())
1725  
    {
1751  
    {
1726  
        reserve_impl(
1752  
        reserve_impl(
1727  
            impl_.offset(id_user) + ref.size(), op);
1753  
            impl_.offset(id_user) + ref.size(), op);
1728  
        set_encoded_authority(
1754  
        set_encoded_authority(
1729  
            ref.encoded_authority());
1755  
            ref.encoded_authority());
1730  
        set_encoded_path(
1756  
        set_encoded_path(
1731  
            ref.encoded_path());
1757  
            ref.encoded_path());
1732  
        if (ref.encoded_path().empty())
1758  
        if (ref.encoded_path().empty())
1733  
            set_path_absolute(false);
1759  
            set_path_absolute(false);
1734  
        else
1760  
        else
1735  
            normalize_path();
1761  
            normalize_path();
1736  
        if(ref.has_query())
1762  
        if(ref.has_query())
1737  
            set_encoded_query(
1763  
            set_encoded_query(
1738  
                ref.encoded_query());
1764  
                ref.encoded_query());
1739  
        else
1765  
        else
1740  
            remove_query();
1766  
            remove_query();
1741  
        if(ref.has_fragment())
1767  
        if(ref.has_fragment())
1742  
            set_encoded_fragment(
1768  
            set_encoded_fragment(
1743  
                ref.encoded_fragment());
1769  
                ref.encoded_fragment());
1744  
        else
1770  
        else
1745  
            remove_fragment();
1771  
            remove_fragment();
1746  
        return {};
1772  
        return {};
1747  
    }
1773  
    }
1748  
    if(ref.encoded_path().empty())
1774  
    if(ref.encoded_path().empty())
1749  
    {
1775  
    {
1750  
        reserve_impl(
1776  
        reserve_impl(
1751  
            impl_.offset(id_query) +
1777  
            impl_.offset(id_query) +
1752  
            ref.size(), op);
1778  
            ref.size(), op);
1753  
        normalize_path();
1779  
        normalize_path();
1754  
        if(ref.has_query())
1780  
        if(ref.has_query())
1755  
        {
1781  
        {
1756  
            set_encoded_query(
1782  
            set_encoded_query(
1757  
                ref.encoded_query());
1783  
                ref.encoded_query());
1758  
        }
1784  
        }
1759  
        if(ref.has_fragment())
1785  
        if(ref.has_fragment())
1760  
            set_encoded_fragment(
1786  
            set_encoded_fragment(
1761  
                ref.encoded_fragment());
1787  
                ref.encoded_fragment());
1762  
        else
1788  
        else
1763  
            remove_fragment();
1789  
            remove_fragment();
1764  
        return {};
1790  
        return {};
1765  
    }
1791  
    }
1766  
    if(ref.is_path_absolute())
1792  
    if(ref.is_path_absolute())
1767  
    {
1793  
    {
1768  
        reserve_impl(
1794  
        reserve_impl(
1769  
            impl_.offset(id_path) +
1795  
            impl_.offset(id_path) +
1770  
                ref.size(), op);
1796  
                ref.size(), op);
1771  
        set_encoded_path(
1797  
        set_encoded_path(
1772  
            ref.encoded_path());
1798  
            ref.encoded_path());
1773  
        normalize_path();
1799  
        normalize_path();
1774  
        if(ref.has_query())
1800  
        if(ref.has_query())
1775  
            set_encoded_query(
1801  
            set_encoded_query(
1776  
                ref.encoded_query());
1802  
                ref.encoded_query());
1777  
        else
1803  
        else
1778  
            remove_query();
1804  
            remove_query();
1779  
        if(ref.has_fragment())
1805  
        if(ref.has_fragment())
1780  
            set_encoded_fragment(
1806  
            set_encoded_fragment(
1781  
                ref.encoded_fragment());
1807  
                ref.encoded_fragment());
1782  
        else
1808  
        else
1783  
            remove_fragment();
1809  
            remove_fragment();
1784  
        return {};
1810  
        return {};
1785  
    }
1811  
    }
1786  
    // General case: ref is relative path
1812  
    // General case: ref is relative path
1787  
    reserve_impl(
1813  
    reserve_impl(
1788  
        impl_.offset(id_query) +
1814  
        impl_.offset(id_query) +
1789  
        ref.size(), op);
1815  
        ref.size(), op);
1790  
    // 5.2.3. Merge Paths
1816  
    // 5.2.3. Merge Paths
1791  
    auto es = encoded_segments();
1817  
    auto es = encoded_segments();
1792  
    if(es.size() > 0)
1818  
    if(es.size() > 0)
1793  
    {
1819  
    {
1794  
        es.pop_back();
1820  
        es.pop_back();
1795  
    }
1821  
    }
1796  
    es.insert(es.end(),
1822  
    es.insert(es.end(),
1797  
        ref.encoded_segments().begin(),
1823  
        ref.encoded_segments().begin(),
1798  
        ref.encoded_segments().end());
1824  
        ref.encoded_segments().end());
1799  
    normalize_path();
1825  
    normalize_path();
1800  
    if(ref.has_query())
1826  
    if(ref.has_query())
1801  
        set_encoded_query(
1827  
        set_encoded_query(
1802  
            ref.encoded_query());
1828  
            ref.encoded_query());
1803  
    else
1829  
    else
1804  
        remove_query();
1830  
        remove_query();
1805  
    if(ref.has_fragment())
1831  
    if(ref.has_fragment())
1806  
        set_encoded_fragment(
1832  
        set_encoded_fragment(
1807  
            ref.encoded_fragment());
1833  
            ref.encoded_fragment());
1808  
    else
1834  
    else
1809  
        remove_fragment();
1835  
        remove_fragment();
1810  
    return {};
1836  
    return {};
1811  
}
1837  
}
1812  

1838  

1813  
//------------------------------------------------
1839  
//------------------------------------------------
1814  
//
1840  
//
1815  
// Normalization
1841  
// Normalization
1816  
//
1842  
//
1817  
//------------------------------------------------
1843  
//------------------------------------------------
1818  

1844  

1819  
template <
1845  
template <
1820  
    class AllowedCharset,
1846  
    class AllowedCharset,
1821  
    class IgnoredCharset>
1847  
    class IgnoredCharset>
1822  
void
1848  
void
1823  
url_base::
1849  
url_base::
1824  
normalize_octets_impl(
1850  
normalize_octets_impl(
1825  
    int id,
1851  
    int id,
1826  
    AllowedCharset const& allowed,
1852  
    AllowedCharset const& allowed,
1827  
    IgnoredCharset const& ignored,
1853  
    IgnoredCharset const& ignored,
1828  
    op_t& op) noexcept
1854  
    op_t& op) noexcept
1829  
{
1855  
{
1830  
    char* it = s_ + impl_.offset(id);
1856  
    char* it = s_ + impl_.offset(id);
1831  
    char* end = s_ + impl_.offset(id + 1);
1857  
    char* end = s_ + impl_.offset(id + 1);
1832  
    char d = 0;
1858  
    char d = 0;
1833  
    char* dest = it;
1859  
    char* dest = it;
1834  
    while (it < end)
1860  
    while (it < end)
1835  
    {
1861  
    {
1836  
        if (*it != '%')
1862  
        if (*it != '%')
1837  
        {
1863  
        {
1838  
            *dest = *it;
1864  
            *dest = *it;
1839  
            ++it;
1865  
            ++it;
1840  
            ++dest;
1866  
            ++dest;
1841  
            continue;
1867  
            continue;
1842  
        }
1868  
        }
1843  
        BOOST_ASSERT(end - it >= 3);
1869  
        BOOST_ASSERT(end - it >= 3);
1844  

1870  

1845  
        // decode unreserved octets
1871  
        // decode unreserved octets
1846  
        d = detail::decode_one(it + 1);
1872  
        d = detail::decode_one(it + 1);
1847  
        if (allowed(d) &&
1873  
        if (allowed(d) &&
1848  
            !ignored(d))
1874  
            !ignored(d))
1849  
        {
1875  
        {
1850  
            *dest = d;
1876  
            *dest = d;
1851  
            it += 3;
1877  
            it += 3;
1852  
            ++dest;
1878  
            ++dest;
1853  
            continue;
1879  
            continue;
1854  
        }
1880  
        }
1855  

1881  

1856  
        // uppercase percent-encoding triplets
1882  
        // uppercase percent-encoding triplets
1857  
        *dest++ = '%';
1883  
        *dest++ = '%';
1858  
        ++it;
1884  
        ++it;
1859  
        *dest++ = grammar::to_upper(*it++);
1885  
        *dest++ = grammar::to_upper(*it++);
1860  
        *dest++ = grammar::to_upper(*it++);
1886  
        *dest++ = grammar::to_upper(*it++);
1861  
    }
1887  
    }
1862  
    if (it != dest)
1888  
    if (it != dest)
1863  
    {
1889  
    {
1864  
        auto diff = it - dest;
1890  
        auto diff = it - dest;
1865  
        auto n = impl_.len(id) - diff;
1891  
        auto n = impl_.len(id) - diff;
1866  
        shrink_impl(id, n, op);
1892  
        shrink_impl(id, n, op);
1867  
        s_[size()] = '\0';
1893  
        s_[size()] = '\0';
1868  
    }
1894  
    }
1869  
}
1895  
}
1870  

1896  

1871  
template<class CharSet>
1897  
template<class CharSet>
1872  
void
1898  
void
1873  
url_base::
1899  
url_base::
1874  
normalize_octets_impl(
1900  
normalize_octets_impl(
1875  
    int idx,
1901  
    int idx,
1876  
    CharSet const& allowed,
1902  
    CharSet const& allowed,
1877  
    op_t& op) noexcept
1903  
    op_t& op) noexcept
1878  
{
1904  
{
1879  
    return normalize_octets_impl(
1905  
    return normalize_octets_impl(
1880  
        idx, allowed, detail::empty_chars, op);
1906  
        idx, allowed, detail::empty_chars, op);
1881  
}
1907  
}
1882  

1908  

1883  
url_base&
1909  
url_base&
1884  
url_base::
1910  
url_base::
1885  
normalize_scheme()
1911  
normalize_scheme()
1886  
{
1912  
{
1887  
    to_lower_impl(id_scheme);
1913  
    to_lower_impl(id_scheme);
1888  
    return *this;
1914  
    return *this;
1889  
}
1915  
}
1890  

1916  

1891  
url_base&
1917  
url_base&
1892  
url_base::
1918  
url_base::
1893  
normalize_authority()
1919  
normalize_authority()
1894  
{
1920  
{
1895  
    op_t op(*this);
1921  
    op_t op(*this);
1896  

1922  

1897  
    // normalize host
1923  
    // normalize host
1898  
    if (host_type() == urls::host_type::name)
1924  
    if (host_type() == urls::host_type::name)
1899  
    {
1925  
    {
1900  
        normalize_octets_impl(
1926  
        normalize_octets_impl(
1901  
            id_host,
1927  
            id_host,
1902  
            detail::reg_name_chars, op);
1928  
            detail::reg_name_chars, op);
1903  
    }
1929  
    }
1904  
    decoded_to_lower_impl(id_host);
1930  
    decoded_to_lower_impl(id_host);
1905  

1931  

1906  
    // normalize password
1932  
    // normalize password
1907  
    normalize_octets_impl(id_pass, detail::password_chars, op);
1933  
    normalize_octets_impl(id_pass, detail::password_chars, op);
1908  

1934  

1909  
    // normalize user
1935  
    // normalize user
1910  
    normalize_octets_impl(id_user, detail::user_chars, op);
1936  
    normalize_octets_impl(id_user, detail::user_chars, op);
1911  
    return *this;
1937  
    return *this;
1912  
}
1938  
}
1913  

1939  

1914  
url_base&
1940  
url_base&
1915  
url_base::
1941  
url_base::
1916  
normalize_path()
1942  
normalize_path()
1917  
{
1943  
{
1918  
    op_t op(*this);
1944  
    op_t op(*this);
1919  
    normalize_octets_impl(id_path, detail::segment_chars, op);
1945  
    normalize_octets_impl(id_path, detail::segment_chars, op);
1920  
    core::string_view p = impl_.get(id_path);
1946  
    core::string_view p = impl_.get(id_path);
1921  
    char* p_dest = s_ + impl_.offset(id_path);
1947  
    char* p_dest = s_ + impl_.offset(id_path);
1922  
    char* p_end = s_ + impl_.offset(id_path + 1);
1948  
    char* p_end = s_ + impl_.offset(id_path + 1);
1923  
    auto pn = p.size();
1949  
    auto pn = p.size();
1924  
    auto skip_dot = 0;
1950  
    auto skip_dot = 0;
1925  
    bool encode_colons = false;
1951  
    bool encode_colons = false;
1926  
    core::string_view first_seg;
1952  
    core::string_view first_seg;
1927  

1953  

1928  
//------------------------------------------------
1954  
//------------------------------------------------
1929  
//
1955  
//
1930  
//  Determine unnecessary initial dot segments to skip and
1956  
//  Determine unnecessary initial dot segments to skip and
1931  
//  if we need to encode colons in the first segment
1957  
//  if we need to encode colons in the first segment
1932  
//
1958  
//
1933  
    if (
1959  
    if (
1934  
        !has_authority() &&
1960  
        !has_authority() &&
1935  
        p.starts_with("/./"))
1961  
        p.starts_with("/./"))
1936  
    {
1962  
    {
1937  
        // check if removing the "/./" would result in "//"
1963  
        // check if removing the "/./" would result in "//"
1938  
        // ex: "/.//", "/././/", "/././/", ...
1964  
        // ex: "/.//", "/././/", "/././/", ...
1939  
        skip_dot = 2;
1965  
        skip_dot = 2;
1940  
        while (p.substr(skip_dot, 3).starts_with("/./"))
1966  
        while (p.substr(skip_dot, 3).starts_with("/./"))
1941  
            skip_dot += 2;
1967  
            skip_dot += 2;
1942  
        if (p.substr(skip_dot).starts_with("//"))
1968  
        if (p.substr(skip_dot).starts_with("//"))
1943  
            skip_dot = 2;
1969  
            skip_dot = 2;
1944  
        else
1970  
        else
1945  
            skip_dot = 0;
1971  
            skip_dot = 0;
1946  
    }
1972  
    }
1947  
    else if (
1973  
    else if (
1948  
        !has_scheme() &&
1974  
        !has_scheme() &&
1949  
        !has_authority())
1975  
        !has_authority())
1950  
    {
1976  
    {
1951  
        if (p.starts_with("./"))
1977  
        if (p.starts_with("./"))
1952  
        {
1978  
        {
1953  
            // check if removing the "./" would result in "//"
1979  
            // check if removing the "./" would result in "//"
1954  
            // ex: ".//", "././/", "././/", ...
1980  
            // ex: ".//", "././/", "././/", ...
1955  
            skip_dot = 1;
1981  
            skip_dot = 1;
1956  
            while (p.substr(skip_dot, 3).starts_with("/./"))
1982  
            while (p.substr(skip_dot, 3).starts_with("/./"))
1957  
                skip_dot += 2;
1983  
                skip_dot += 2;
1958  
            if (p.substr(skip_dot).starts_with("//"))
1984  
            if (p.substr(skip_dot).starts_with("//"))
1959  
                skip_dot = 2;
1985  
                skip_dot = 2;
1960  
            else
1986  
            else
1961  
                skip_dot = 0;
1987  
                skip_dot = 0;
1962  

1988  

1963  
            if ( !skip_dot )
1989  
            if ( !skip_dot )
1964  
            {
1990  
            {
1965  
                // check if removing "./"s would leave us
1991  
                // check if removing "./"s would leave us
1966  
                // a first segment with an ambiguous ":"
1992  
                // a first segment with an ambiguous ":"
1967  
                first_seg = p.substr(2);
1993  
                first_seg = p.substr(2);
1968  
                while (first_seg.starts_with("./"))
1994  
                while (first_seg.starts_with("./"))
1969  
                    first_seg = first_seg.substr(2);
1995  
                    first_seg = first_seg.substr(2);
1970  
                auto i = first_seg.find('/');
1996  
                auto i = first_seg.find('/');
1971  
                if (i != core::string_view::npos)
1997  
                if (i != core::string_view::npos)
1972  
                    first_seg = first_seg.substr(0, i);
1998  
                    first_seg = first_seg.substr(0, i);
1973  
                encode_colons = first_seg.contains(':');
1999  
                encode_colons = first_seg.contains(':');
1974  
            }
2000  
            }
1975  
        }
2001  
        }
1976  
        else
2002  
        else
1977  
        {
2003  
        {
1978  
            // check if normalize_octets_impl
2004  
            // check if normalize_octets_impl
1979  
            // didn't already create a ":"
2005  
            // didn't already create a ":"
1980  
            // in the first segment
2006  
            // in the first segment
1981  
            first_seg = p;
2007  
            first_seg = p;
1982  
            auto i = first_seg.find('/');
2008  
            auto i = first_seg.find('/');
1983  
            if (i != core::string_view::npos)
2009  
            if (i != core::string_view::npos)
1984  
                first_seg = p.substr(0, i);
2010  
                first_seg = p.substr(0, i);
1985  
            encode_colons = first_seg.contains(':');
2011  
            encode_colons = first_seg.contains(':');
1986  
        }
2012  
        }
1987  
    }
2013  
    }
1988  

2014  

1989  
//------------------------------------------------
2015  
//------------------------------------------------
1990  
//
2016  
//
1991  
//  Encode colons in the first segment
2017  
//  Encode colons in the first segment
1992  
//
2018  
//
1993  
    if (encode_colons)
2019  
    if (encode_colons)
1994  
    {
2020  
    {
1995  
        // prepend with "./"
2021  
        // prepend with "./"
1996  
        // (resize_impl never throws)
2022  
        // (resize_impl never throws)
1997  
        auto cn =
2023  
        auto cn =
1998  
            std::count(
2024  
            std::count(
1999  
                first_seg.begin(),
2025  
                first_seg.begin(),
2000  
                first_seg.end(),
2026  
                first_seg.end(),
2001  
                ':');
2027  
                ':');
2002  
        resize_impl(
2028  
        resize_impl(
2003  
            id_path, pn + (2 * cn), op);
2029  
            id_path, pn + (2 * cn), op);
2004  
        // move the 2nd, 3rd, ... segments
2030  
        // move the 2nd, 3rd, ... segments
2005  
        auto begin = s_ + impl_.offset(id_path);
2031  
        auto begin = s_ + impl_.offset(id_path);
2006  
        auto it = begin;
2032  
        auto it = begin;
2007  
        auto end = begin + pn;
2033  
        auto end = begin + pn;
2008  
        while (core::string_view(it, 2) == "./")
2034  
        while (core::string_view(it, 2) == "./")
2009  
            it += 2;
2035  
            it += 2;
2010  
        while (*it != '/' &&
2036  
        while (*it != '/' &&
2011  
               it != end)
2037  
               it != end)
2012  
            ++it;
2038  
            ++it;
2013  
        // we don't need op here because this is
2039  
        // we don't need op here because this is
2014  
        // an internal operation
2040  
        // an internal operation
2015  
        std::memmove(it + (2 * cn), it, end - it);
2041  
        std::memmove(it + (2 * cn), it, end - it);
2016  

2042  

2017  
        // move 1st segment
2043  
        // move 1st segment
2018  
        auto src = s_ + impl_.offset(id_path) + pn;
2044  
        auto src = s_ + impl_.offset(id_path) + pn;
2019  
        auto dest = s_ + impl_.offset(id_query);
2045  
        auto dest = s_ + impl_.offset(id_query);
2020  
        src -= end - it;
2046  
        src -= end - it;
2021  
        dest -= end - it;
2047  
        dest -= end - it;
2022  
        pn -= end - it;
2048  
        pn -= end - it;
2023  
        do {
2049  
        do {
2024  
            --src;
2050  
            --src;
2025  
            --dest;
2051  
            --dest;
2026  
            if (*src != ':')
2052  
            if (*src != ':')
2027  
            {
2053  
            {
2028  
                *dest = *src;
2054  
                *dest = *src;
2029  
            }
2055  
            }
2030  
            else
2056  
            else
2031  
            {
2057  
            {
2032  
                // use uppercase as required by
2058  
                // use uppercase as required by
2033  
                // syntax-based normalization
2059  
                // syntax-based normalization
2034  
                *dest-- = 'A';
2060  
                *dest-- = 'A';
2035  
                *dest-- = '3';
2061  
                *dest-- = '3';
2036  
                *dest = '%';
2062  
                *dest = '%';
2037  
            }
2063  
            }
2038  
            --pn;
2064  
            --pn;
2039  
        } while (pn);
2065  
        } while (pn);
2040  
        skip_dot = 0;
2066  
        skip_dot = 0;
2041  
        p = impl_.get(id_path);
2067  
        p = impl_.get(id_path);
2042  
        pn = p.size();
2068  
        pn = p.size();
2043  
        p_dest = s_ + impl_.offset(id_path);
2069  
        p_dest = s_ + impl_.offset(id_path);
2044  
        p_end = s_ + impl_.offset(id_path + 1);
2070  
        p_end = s_ + impl_.offset(id_path + 1);
2045  
    }
2071  
    }
2046  

2072  

2047  
//------------------------------------------------
2073  
//------------------------------------------------
2048  
//
2074  
//
2049  
//  Remove "." and ".." segments
2075  
//  Remove "." and ".." segments
2050  
//
2076  
//
2051  
    p.remove_prefix(skip_dot);
2077  
    p.remove_prefix(skip_dot);
2052  
    p_dest += skip_dot;
2078  
    p_dest += skip_dot;
2053  
    auto n = detail::remove_dot_segments(
2079  
    auto n = detail::remove_dot_segments(
2054  
        p_dest, p_end, p);
2080  
        p_dest, p_end, p);
2055  

2081  

2056  
//------------------------------------------------
2082  
//------------------------------------------------
2057  
//
2083  
//
2058  
//  Update path parameters
2084  
//  Update path parameters
2059  
//
2085  
//
2060  
    if (n != pn)
2086  
    if (n != pn)
2061  
    {
2087  
    {
2062  
        BOOST_ASSERT(n < pn);
2088  
        BOOST_ASSERT(n < pn);
2063  
        shrink_impl(id_path, n + skip_dot, op);
2089  
        shrink_impl(id_path, n + skip_dot, op);
2064  
        p = encoded_path();
2090  
        p = encoded_path();
2065  
        if (p == "/")
2091  
        if (p == "/")
2066  
            impl_.nseg_ = 0;
2092  
            impl_.nseg_ = 0;
2067  
        else if (!p.empty())
2093  
        else if (!p.empty())
2068 -
            impl_.nseg_ = std::count(
2094 +
            impl_.nseg_ = detail::to_size_type(
2069 -
                p.begin() + 1, p.end(), '/') + 1;
2095 +
                std::count(
 
2096 +
                    p.begin() + 1, p.end(), '/') + 1);
2070  
        else
2097  
        else
2071  
            impl_.nseg_ = 0;
2098  
            impl_.nseg_ = 0;
2072  
        impl_.decoded_[id_path] =
2099  
        impl_.decoded_[id_path] =
2073 -
            detail::decode_bytes_unsafe(impl_.get(id_path));
2100 +
            detail::to_size_type(detail::decode_bytes_unsafe(
 
2101 +
                impl_.get(id_path)));
2074  
    }
2102  
    }
2075  
    return *this;
2103  
    return *this;
2076  
}
2104  
}
2077  

2105  

2078  
url_base&
2106  
url_base&
2079  
url_base::
2107  
url_base::
2080  
normalize_query()
2108  
normalize_query()
2081  
{
2109  
{
2082  
    op_t op(*this);
2110  
    op_t op(*this);
2083  
    normalize_octets_impl(
2111  
    normalize_octets_impl(
2084  
        id_query,
2112  
        id_query,
2085  
        detail::query_chars,
2113  
        detail::query_chars,
2086  
        detail::query_ignore_chars,
2114  
        detail::query_ignore_chars,
2087  
        op);
2115  
        op);
2088  
    return *this;
2116  
    return *this;
2089  
}
2117  
}
2090  

2118  

2091  
url_base&
2119  
url_base&
2092  
url_base::
2120  
url_base::
2093  
normalize_fragment()
2121  
normalize_fragment()
2094  
{
2122  
{
2095  
    op_t op(*this);
2123  
    op_t op(*this);
2096  
    normalize_octets_impl(
2124  
    normalize_octets_impl(
2097  
        id_frag, detail::fragment_chars, op);
2125  
        id_frag, detail::fragment_chars, op);
2098  
    return *this;
2126  
    return *this;
2099  
}
2127  
}
2100  

2128  

2101  
url_base&
2129  
url_base&
2102  
url_base::
2130  
url_base::
2103  
normalize()
2131  
normalize()
2104  
{
2132  
{
2105  
    normalize_fragment();
2133  
    normalize_fragment();
2106  
    normalize_query();
2134  
    normalize_query();
2107  
    normalize_path();
2135  
    normalize_path();
2108  
    normalize_authority();
2136  
    normalize_authority();
2109  
    normalize_scheme();
2137  
    normalize_scheme();
2110  
    return *this;
2138  
    return *this;
2111  
}
2139  
}
2112  

2140  

2113  
//------------------------------------------------
2141  
//------------------------------------------------
2114  
//
2142  
//
2115  
// Implementation
2143  
// Implementation
2116  
//
2144  
//
2117  
//------------------------------------------------
2145  
//------------------------------------------------
2118  

2146  

2119  
void
2147  
void
2120  
url_base::
2148  
url_base::
2121  
check_invariants() const noexcept
2149  
check_invariants() const noexcept
2122  
{
2150  
{
2123  
    BOOST_ASSERT(pi_);
2151  
    BOOST_ASSERT(pi_);
2124  
    BOOST_ASSERT(
2152  
    BOOST_ASSERT(
2125  
        impl_.len(id_scheme) == 0 ||
2153  
        impl_.len(id_scheme) == 0 ||
2126  
        impl_.get(id_scheme).ends_with(':'));
2154  
        impl_.get(id_scheme).ends_with(':'));
2127  
    BOOST_ASSERT(
2155  
    BOOST_ASSERT(
2128  
        impl_.len(id_user) == 0 ||
2156  
        impl_.len(id_user) == 0 ||
2129  
        impl_.get(id_user).starts_with("//"));
2157  
        impl_.get(id_user).starts_with("//"));
2130  
    BOOST_ASSERT(
2158  
    BOOST_ASSERT(
2131  
        impl_.len(id_pass) == 0 ||
2159  
        impl_.len(id_pass) == 0 ||
2132  
        impl_.get(id_user).starts_with("//"));
2160  
        impl_.get(id_user).starts_with("//"));
2133  
    BOOST_ASSERT(
2161  
    BOOST_ASSERT(
2134  
        impl_.len(id_pass) == 0 ||
2162  
        impl_.len(id_pass) == 0 ||
2135  
        (impl_.len(id_pass) == 1 &&
2163  
        (impl_.len(id_pass) == 1 &&
2136  
            impl_.get(id_pass) == "@") ||
2164  
            impl_.get(id_pass) == "@") ||
2137  
        (impl_.len(id_pass) > 1 &&
2165  
        (impl_.len(id_pass) > 1 &&
2138  
            impl_.get(id_pass).starts_with(':') &&
2166  
            impl_.get(id_pass).starts_with(':') &&
2139  
            impl_.get(id_pass).ends_with('@')));
2167  
            impl_.get(id_pass).ends_with('@')));
2140  
    BOOST_ASSERT(
2168  
    BOOST_ASSERT(
2141  
        impl_.len(id_user, id_path) == 0 ||
2169  
        impl_.len(id_user, id_path) == 0 ||
2142  
        impl_.get(id_user).starts_with("//"));
2170  
        impl_.get(id_user).starts_with("//"));
2143  
    BOOST_ASSERT(impl_.decoded_[id_path] >=
2171  
    BOOST_ASSERT(impl_.decoded_[id_path] >=
2144  
        ((impl_.len(id_path) + 2) / 3));
2172  
        ((impl_.len(id_path) + 2) / 3));
2145  
    BOOST_ASSERT(
2173  
    BOOST_ASSERT(
2146  
        impl_.len(id_port) == 0 ||
2174  
        impl_.len(id_port) == 0 ||
2147  
        impl_.get(id_port).starts_with(':'));
2175  
        impl_.get(id_port).starts_with(':'));
2148  
    BOOST_ASSERT(
2176  
    BOOST_ASSERT(
2149  
        impl_.len(id_query) == 0 ||
2177  
        impl_.len(id_query) == 0 ||
2150  
        impl_.get(id_query).starts_with('?'));
2178  
        impl_.get(id_query).starts_with('?'));
2151  
    BOOST_ASSERT(
2179  
    BOOST_ASSERT(
2152  
        (impl_.len(id_query) == 0 && impl_.nparam_ == 0) ||
2180  
        (impl_.len(id_query) == 0 && impl_.nparam_ == 0) ||
2153  
        (impl_.len(id_query) > 0 && impl_.nparam_ > 0));
2181  
        (impl_.len(id_query) > 0 && impl_.nparam_ > 0));
2154  
    BOOST_ASSERT(
2182  
    BOOST_ASSERT(
2155  
        impl_.len(id_frag) == 0 ||
2183  
        impl_.len(id_frag) == 0 ||
2156  
        impl_.get(id_frag).starts_with('#'));
2184  
        impl_.get(id_frag).starts_with('#'));
2157  
    BOOST_ASSERT(c_str()[size()] == '\0');
2185  
    BOOST_ASSERT(c_str()[size()] == '\0');
2158  
}
2186  
}
2159  

2187  

2160  
char*
2188  
char*
2161  
url_base::
2189  
url_base::
2162  
resize_impl(
2190  
resize_impl(
2163  
    int id,
2191  
    int id,
2164  
    std::size_t new_size,
2192  
    std::size_t new_size,
2165  
    op_t& op)
2193  
    op_t& op)
2166  
{
2194  
{
2167  
    return resize_impl(
2195  
    return resize_impl(
2168  
        id, id + 1, new_size, op);
2196  
        id, id + 1, new_size, op);
2169  
}
2197  
}
2170  

2198  

2171  
char*
2199  
char*
2172  
url_base::
2200  
url_base::
2173  
resize_impl(
2201  
resize_impl(
2174  
    int first,
2202  
    int first,
2175  
    int last,
2203  
    int last,
2176  
    std::size_t new_len,
2204  
    std::size_t new_len,
2177  
    op_t& op)
2205  
    op_t& op)
2178  
{
2206  
{
2179  
    auto const n0 = impl_.len(first, last);
2207  
    auto const n0 = impl_.len(first, last);
2180  
    if(new_len == 0 && n0 == 0)
2208  
    if(new_len == 0 && n0 == 0)
2181  
        return s_ + impl_.offset(first);
2209  
        return s_ + impl_.offset(first);
2182  
    if(new_len <= n0)
2210  
    if(new_len <= n0)
2183  
        return shrink_impl(
2211  
        return shrink_impl(
2184  
            first, last, new_len, op);
2212  
            first, last, new_len, op);
2185  

2213  

2186  
    // growing
2214  
    // growing
2187  
    std::size_t n = new_len - n0;
2215  
    std::size_t n = new_len - n0;
2188  
    reserve_impl(size() + n, op);
2216  
    reserve_impl(size() + n, op);
2189  
    auto const pos =
2217  
    auto const pos =
2190  
        impl_.offset(last);
2218  
        impl_.offset(last);
2191  
    // adjust chars
2219  
    // adjust chars
2192  
    op.move(
2220  
    op.move(
2193  
        s_ + pos + n,
2221  
        s_ + pos + n,
2194  
        s_ + pos,
2222  
        s_ + pos,
2195  
        impl_.offset(id_end) -
2223  
        impl_.offset(id_end) -
2196  
            pos + 1);
2224  
            pos + 1);
2197  
    // collapse (first, last)
2225  
    // collapse (first, last)
2198  
    impl_.collapse(first, last,
2226  
    impl_.collapse(first, last,
2199  
        impl_.offset(last) + n);
2227  
        impl_.offset(last) + n);
2200  
    // shift (last, end) right
2228  
    // shift (last, end) right
2201  
    impl_.adjust_right(last, id_end, n);
2229  
    impl_.adjust_right(last, id_end, n);
2202  
    s_[size()] = '\0';
2230  
    s_[size()] = '\0';
2203  
    return s_ + impl_.offset(first);
2231  
    return s_ + impl_.offset(first);
2204  
}
2232  
}
2205  

2233  

2206  
char*
2234  
char*
2207  
url_base::
2235  
url_base::
2208  
shrink_impl(
2236  
shrink_impl(
2209  
    int id,
2237  
    int id,
2210  
    std::size_t new_size,
2238  
    std::size_t new_size,
2211  
    op_t& op)
2239  
    op_t& op)
2212  
{
2240  
{
2213  
    return shrink_impl(
2241  
    return shrink_impl(
2214  
        id, id + 1, new_size, op);
2242  
        id, id + 1, new_size, op);
2215  
}
2243  
}
2216  

2244  

2217  
char*
2245  
char*
2218  
url_base::
2246  
url_base::
2219  
shrink_impl(
2247  
shrink_impl(
2220  
    int first,
2248  
    int first,
2221  
    int last,
2249  
    int last,
2222  
    std::size_t new_len,
2250  
    std::size_t new_len,
2223  
    op_t& op)
2251  
    op_t& op)
2224  
{
2252  
{
2225  
    // shrinking
2253  
    // shrinking
2226  
    auto const n0 = impl_.len(first, last);
2254  
    auto const n0 = impl_.len(first, last);
2227  
    BOOST_ASSERT(new_len <= n0);
2255  
    BOOST_ASSERT(new_len <= n0);
2228  
    std::size_t n = n0 - new_len;
2256  
    std::size_t n = n0 - new_len;
2229  
    auto const pos =
2257  
    auto const pos =
2230  
        impl_.offset(last);
2258  
        impl_.offset(last);
2231  
    // adjust chars
2259  
    // adjust chars
2232  
    op.move(
2260  
    op.move(
2233  
        s_ + pos - n,
2261  
        s_ + pos - n,
2234  
        s_ + pos,
2262  
        s_ + pos,
2235  
        impl_.offset(
2263  
        impl_.offset(
2236  
            id_end) - pos + 1);
2264  
            id_end) - pos + 1);
2237  
    // collapse (first, last)
2265  
    // collapse (first, last)
2238  
    impl_.collapse(first,  last,
2266  
    impl_.collapse(first,  last,
2239  
        impl_.offset(last) - n);
2267  
        impl_.offset(last) - n);
2240  
    // shift (last, end) left
2268  
    // shift (last, end) left
2241  
    impl_.adjust_left(last, id_end, n);
2269  
    impl_.adjust_left(last, id_end, n);
2242  
    s_[size()] = '\0';
2270  
    s_[size()] = '\0';
2243  
    return s_ + impl_.offset(first);
2271  
    return s_ + impl_.offset(first);
2244  
}
2272  
}
2245  

2273  

2246  
//------------------------------------------------
2274  
//------------------------------------------------
2247  

2275  

2248  
void
2276  
void
2249  
url_base::
2277  
url_base::
2250  
set_scheme_impl(
2278  
set_scheme_impl(
2251  
    core::string_view s,
2279  
    core::string_view s,
2252  
    urls::scheme id)
2280  
    urls::scheme id)
2253  
{
2281  
{
2254  
    op_t op(*this, &s);
2282  
    op_t op(*this, &s);
2255  
    check_invariants();
2283  
    check_invariants();
2256  
    grammar::parse(
2284  
    grammar::parse(
2257  
        s, detail::scheme_rule()
2285  
        s, detail::scheme_rule()
2258  
            ).value(BOOST_URL_POS);
2286  
            ).value(BOOST_URL_POS);
2259  
    auto const n = s.size();
2287  
    auto const n = s.size();
2260  
    auto const p = impl_.offset(id_path);
2288  
    auto const p = impl_.offset(id_path);
2261  

2289  

2262  
    // check for "./" prefix
2290  
    // check for "./" prefix
2263  
    bool const has_dot =
2291  
    bool const has_dot =
2264  
        [this, p]
2292  
        [this, p]
2265  
    {
2293  
    {
2266  
        if(impl_.nseg_ == 0)
2294  
        if(impl_.nseg_ == 0)
2267  
            return false;
2295  
            return false;
2268  
        if(first_segment().size() < 2)
2296  
        if(first_segment().size() < 2)
2269  
            return false;
2297  
            return false;
2270  
        auto const src = s_ + p;
2298  
        auto const src = s_ + p;
2271  
        if(src[0] != '.')
2299  
        if(src[0] != '.')
2272  
            return false;
2300  
            return false;
2273  
        if(src[1] != '/')
2301  
        if(src[1] != '/')
2274  
            return false;
2302  
            return false;
2275  
        return true;
2303  
        return true;
2276  
    }();
2304  
    }();
2277  

2305  

2278  
    // Remove "./"
2306  
    // Remove "./"
2279  
    if(has_dot)
2307  
    if(has_dot)
2280  
    {
2308  
    {
2281  
        // do this first, for
2309  
        // do this first, for
2282  
        // strong exception safety
2310  
        // strong exception safety
2283  
        reserve_impl(
2311  
        reserve_impl(
2284  
            size() + n + 1 - 2, op);
2312  
            size() + n + 1 - 2, op);
2285  
        op.move(
2313  
        op.move(
2286  
            s_ + p,
2314  
            s_ + p,
2287  
            s_ + p + 2,
2315  
            s_ + p + 2,
2288  
            size() + 1 -
2316  
            size() + 1 -
2289  
                (p + 2));
2317  
                (p + 2));
2290  
        impl_.set_size(
2318  
        impl_.set_size(
2291  
            id_path,
2319  
            id_path,
2292  
            impl_.len(id_path) - 2);
2320  
            impl_.len(id_path) - 2);
2293  
        s_[size()] = '\0';
2321  
        s_[size()] = '\0';
2294  
    }
2322  
    }
2295  

2323  

2296  
    auto dest = resize_impl(
2324  
    auto dest = resize_impl(
2297  
        id_scheme, n + 1, op);
2325  
        id_scheme, n + 1, op);
2298  
    s.copy(dest, n);
2326  
    s.copy(dest, n);
2299  
    dest[n] = ':';
2327  
    dest[n] = ':';
2300  
    impl_.scheme_ = id;
2328  
    impl_.scheme_ = id;
2301  
    check_invariants();
2329  
    check_invariants();
2302  
}
2330  
}
2303  

2331  

2304  
char*
2332  
char*
2305  
url_base::
2333  
url_base::
2306  
set_user_impl(
2334  
set_user_impl(
2307  
    std::size_t n,
2335  
    std::size_t n,
2308  
    op_t& op)
2336  
    op_t& op)
2309  
{
2337  
{
2310  
    check_invariants();
2338  
    check_invariants();
2311  
    if(impl_.len(id_pass) != 0)
2339  
    if(impl_.len(id_pass) != 0)
2312  
    {
2340  
    {
2313  
        // keep "//"
2341  
        // keep "//"
2314  
        auto dest = resize_impl(
2342  
        auto dest = resize_impl(
2315  
            id_user, 2 + n, op);
2343  
            id_user, 2 + n, op);
2316  
        check_invariants();
2344  
        check_invariants();
2317  
        return dest + 2;
2345  
        return dest + 2;
2318  
    }
2346  
    }
2319  
    // add authority
2347  
    // add authority
2320  
    bool const make_absolute =
2348  
    bool const make_absolute =
2321  
        !is_path_absolute() &&
2349  
        !is_path_absolute() &&
2322  
        !impl_.get(id_path).empty();
2350  
        !impl_.get(id_path).empty();
2323  
    auto dest = resize_impl(
2351  
    auto dest = resize_impl(
2324  
        id_user, 2 + n + 1 + make_absolute, op);
2352  
        id_user, 2 + n + 1 + make_absolute, op);
2325  
    impl_.split(id_user, 2 + n);
2353  
    impl_.split(id_user, 2 + n);
2326  
    dest[0] = '/';
2354  
    dest[0] = '/';
2327  
    dest[1] = '/';
2355  
    dest[1] = '/';
2328  
    dest[2 + n] = '@';
2356  
    dest[2 + n] = '@';
2329  
    if (make_absolute)
2357  
    if (make_absolute)
2330  
    {
2358  
    {
2331  
        impl_.split(id_pass, 1);
2359  
        impl_.split(id_pass, 1);
2332  
        impl_.split(id_host, 0);
2360  
        impl_.split(id_host, 0);
2333  
        impl_.split(id_port, 0);
2361  
        impl_.split(id_port, 0);
2334  
        dest[3 + n] = '/';
2362  
        dest[3 + n] = '/';
2335  
    }
2363  
    }
2336  
    check_invariants();
2364  
    check_invariants();
2337  
    return dest + 2;
2365  
    return dest + 2;
2338  
}
2366  
}
2339  

2367  

2340  
char*
2368  
char*
2341  
url_base::
2369  
url_base::
2342  
set_password_impl(
2370  
set_password_impl(
2343  
    std::size_t n,
2371  
    std::size_t n,
2344  
    op_t& op)
2372  
    op_t& op)
2345  
{
2373  
{
2346  
    check_invariants();
2374  
    check_invariants();
2347  
    if(impl_.len(id_user) != 0)
2375  
    if(impl_.len(id_user) != 0)
2348  
    {
2376  
    {
2349  
        // already have authority
2377  
        // already have authority
2350  
        auto const dest = resize_impl(
2378  
        auto const dest = resize_impl(
2351  
            id_pass, 1 + n + 1, op);
2379  
            id_pass, 1 + n + 1, op);
2352  
        dest[0] = ':';
2380  
        dest[0] = ':';
2353  
        dest[n + 1] = '@';
2381  
        dest[n + 1] = '@';
2354  
        check_invariants();
2382  
        check_invariants();
2355  
        return dest + 1;
2383  
        return dest + 1;
2356  
    }
2384  
    }
2357  
    // add authority
2385  
    // add authority
2358  
    bool const make_absolute =
2386  
    bool const make_absolute =
2359  
            !is_path_absolute() &&
2387  
            !is_path_absolute() &&
2360  
            !impl_.get(id_path).empty();
2388  
            !impl_.get(id_path).empty();
2361  
    auto const dest =
2389  
    auto const dest =
2362  
        resize_impl(
2390  
        resize_impl(
2363  
        id_user, id_host,
2391  
        id_user, id_host,
2364  
        2 + 1 + n + 1 + make_absolute, op);
2392  
        2 + 1 + n + 1 + make_absolute, op);
2365  
    impl_.split(id_user, 2);
2393  
    impl_.split(id_user, 2);
2366  
    dest[0] = '/';
2394  
    dest[0] = '/';
2367  
    dest[1] = '/';
2395  
    dest[1] = '/';
2368  
    dest[2] = ':';
2396  
    dest[2] = ':';
2369  
    dest[2 + n + 1] = '@';
2397  
    dest[2 + n + 1] = '@';
2370  
    if (make_absolute)
2398  
    if (make_absolute)
2371  
    {
2399  
    {
2372  
        impl_.split(id_pass, 2 + n);
2400  
        impl_.split(id_pass, 2 + n);
2373  
        impl_.split(id_host, 0);
2401  
        impl_.split(id_host, 0);
2374  
        impl_.split(id_port, 0);
2402  
        impl_.split(id_port, 0);
2375  
        dest[4 + n] = '/';
2403  
        dest[4 + n] = '/';
2376  
    }
2404  
    }
2377  
    check_invariants();
2405  
    check_invariants();
2378  
    return dest + 3;
2406  
    return dest + 3;
2379  
}
2407  
}
2380  

2408  

2381  
char*
2409  
char*
2382  
url_base::
2410  
url_base::
2383  
set_userinfo_impl(
2411  
set_userinfo_impl(
2384  
    std::size_t n,
2412  
    std::size_t n,
2385  
    op_t& op)
2413  
    op_t& op)
2386  
{
2414  
{
2387  
    // "//" {dest} "@"
2415  
    // "//" {dest} "@"
2388  
    check_invariants();
2416  
    check_invariants();
2389  
    bool const make_absolute =
2417  
    bool const make_absolute =
2390  
            !is_path_absolute() &&
2418  
            !is_path_absolute() &&
2391  
            !impl_.get(id_path).empty();
2419  
            !impl_.get(id_path).empty();
2392  
    auto dest = resize_impl(
2420  
    auto dest = resize_impl(
2393  
        id_user, id_host, n + 3 + make_absolute, op);
2421  
        id_user, id_host, n + 3 + make_absolute, op);
2394  
    impl_.split(id_user, n + 2);
2422  
    impl_.split(id_user, n + 2);
2395  
    dest[0] = '/';
2423  
    dest[0] = '/';
2396  
    dest[1] = '/';
2424  
    dest[1] = '/';
2397  
    dest[n + 2] = '@';
2425  
    dest[n + 2] = '@';
2398  
    if (make_absolute)
2426  
    if (make_absolute)
2399  
    {
2427  
    {
2400  
        impl_.split(id_pass, 1);
2428  
        impl_.split(id_pass, 1);
2401  
        impl_.split(id_host, 0);
2429  
        impl_.split(id_host, 0);
2402  
        impl_.split(id_port, 0);
2430  
        impl_.split(id_port, 0);
2403  
        dest[3 + n] = '/';
2431  
        dest[3 + n] = '/';
2404  
    }
2432  
    }
2405  
    check_invariants();
2433  
    check_invariants();
2406  
    return dest + 2;
2434  
    return dest + 2;
2407  
}
2435  
}
2408  

2436  

2409  
char*
2437  
char*
2410  
url_base::
2438  
url_base::
2411  
set_host_impl(
2439  
set_host_impl(
2412  
    std::size_t n,
2440  
    std::size_t n,
2413  
    op_t& op)
2441  
    op_t& op)
2414  
{
2442  
{
2415  
    check_invariants();
2443  
    check_invariants();
2416  
    if(impl_.len(id_user) == 0)
2444  
    if(impl_.len(id_user) == 0)
2417  
    {
2445  
    {
2418  
        // add authority
2446  
        // add authority
2419  
        bool make_absolute =
2447  
        bool make_absolute =
2420  
            !is_path_absolute() &&
2448  
            !is_path_absolute() &&
2421  
            impl_.len(id_path) != 0;
2449  
            impl_.len(id_path) != 0;
2422  
        auto pn = impl_.len(id_path);
2450  
        auto pn = impl_.len(id_path);
2423  
        auto dest = resize_impl(
2451  
        auto dest = resize_impl(
2424  
            id_user, n + 2 + make_absolute, op);
2452  
            id_user, n + 2 + make_absolute, op);
2425  
        impl_.split(id_user, 2);
2453  
        impl_.split(id_user, 2);
2426  
        impl_.split(id_pass, 0);
2454  
        impl_.split(id_pass, 0);
2427  
        impl_.split(id_host, n);
2455  
        impl_.split(id_host, n);
2428  
        impl_.split(id_port, 0);
2456  
        impl_.split(id_port, 0);
2429  
        impl_.split(id_path, pn + make_absolute);
2457  
        impl_.split(id_path, pn + make_absolute);
2430  
        if (make_absolute)
2458  
        if (make_absolute)
2431  
        {
2459  
        {
2432  
            dest[n + 2] = '/';
2460  
            dest[n + 2] = '/';
2433  
            ++impl_.decoded_[id_path];
2461  
            ++impl_.decoded_[id_path];
2434  
        }
2462  
        }
2435  
        dest[0] = '/';
2463  
        dest[0] = '/';
2436  
        dest[1] = '/';
2464  
        dest[1] = '/';
2437  
        check_invariants();
2465  
        check_invariants();
2438  
        return dest + 2;
2466  
        return dest + 2;
2439  
    }
2467  
    }
2440  
    // already have authority
2468  
    // already have authority
2441  
    auto const dest = resize_impl(
2469  
    auto const dest = resize_impl(
2442  
        id_host, n, op);
2470  
        id_host, n, op);
2443  
    check_invariants();
2471  
    check_invariants();
2444  
    return dest;
2472  
    return dest;
2445  
}
2473  
}
2446  

2474  

2447  
char*
2475  
char*
2448  
url_base::
2476  
url_base::
2449  
set_port_impl(
2477  
set_port_impl(
2450  
    std::size_t n,
2478  
    std::size_t n,
2451  
    op_t& op)
2479  
    op_t& op)
2452  
{
2480  
{
2453  
    check_invariants();
2481  
    check_invariants();
2454  
    if(impl_.len(id_user) != 0)
2482  
    if(impl_.len(id_user) != 0)
2455  
    {
2483  
    {
2456  
        // authority exists
2484  
        // authority exists
2457  
        auto dest = resize_impl(
2485  
        auto dest = resize_impl(
2458  
            id_port, n + 1, op);
2486  
            id_port, n + 1, op);
2459  
        dest[0] = ':';
2487  
        dest[0] = ':';
2460  
        check_invariants();
2488  
        check_invariants();
2461  
        return dest + 1;
2489  
        return dest + 1;
2462  
    }
2490  
    }
2463  
    bool make_absolute =
2491  
    bool make_absolute =
2464  
        !is_path_absolute() &&
2492  
        !is_path_absolute() &&
2465  
        impl_.len(id_path) != 0;
2493  
        impl_.len(id_path) != 0;
2466  
    auto dest = resize_impl(
2494  
    auto dest = resize_impl(
2467  
        id_user, 3 + n + make_absolute, op);
2495  
        id_user, 3 + n + make_absolute, op);
2468  
    impl_.split(id_user, 2);
2496  
    impl_.split(id_user, 2);
2469  
    impl_.split(id_pass, 0);
2497  
    impl_.split(id_pass, 0);
2470  
    impl_.split(id_host, 0);
2498  
    impl_.split(id_host, 0);
2471  
    dest[0] = '/';
2499  
    dest[0] = '/';
2472  
    dest[1] = '/';
2500  
    dest[1] = '/';
2473  
    dest[2] = ':';
2501  
    dest[2] = ':';
2474  
    if (make_absolute)
2502  
    if (make_absolute)
2475  
    {
2503  
    {
2476  
        impl_.split(id_port, n + 1);
2504  
        impl_.split(id_port, n + 1);
2477  
        dest[n + 3] = '/';
2505  
        dest[n + 3] = '/';
2478  
        ++impl_.decoded_[id_path];
2506  
        ++impl_.decoded_[id_path];
2479  
    }
2507  
    }
2480  
    check_invariants();
2508  
    check_invariants();
2481  
    return dest + 3;
2509  
    return dest + 3;
2482  
}
2510  
}
2483  

2511  

2484  
char*
2512  
char*
2485  
url_base::
2513  
url_base::
2486  
set_path_impl(
2514  
set_path_impl(
2487  
    std::size_t n,
2515  
    std::size_t n,
2488  
    op_t& op)
2516  
    op_t& op)
2489  
{
2517  
{
2490  
    check_invariants();
2518  
    check_invariants();
2491  
    auto const dest = resize_impl(
2519  
    auto const dest = resize_impl(
2492  
        id_path, n, op);
2520  
        id_path, n, op);
2493  
    return dest;
2521  
    return dest;
2494  
}
2522  
}
2495  

2523  

2496  

2524  

2497  
//------------------------------------------------
2525  
//------------------------------------------------
2498  

2526  

2499  
// return the first segment of the path.
2527  
// return the first segment of the path.
2500  
// this is needed for some algorithms.
2528  
// this is needed for some algorithms.
2501  
core::string_view
2529  
core::string_view
2502  
url_base::
2530  
url_base::
2503  
first_segment() const noexcept
2531  
first_segment() const noexcept
2504  
{
2532  
{
2505  
    if(impl_.nseg_ == 0)
2533  
    if(impl_.nseg_ == 0)
2506  
        return {};
2534  
        return {};
2507  
    auto const p0 = impl_.cs_ +
2535  
    auto const p0 = impl_.cs_ +
2508  
        impl_.offset(id_path) +
2536  
        impl_.offset(id_path) +
2509  
            detail::path_prefix(
2537  
            detail::path_prefix(
2510  
                impl_.get(id_path));
2538  
                impl_.get(id_path));
2511  
    auto const end = impl_.cs_ +
2539  
    auto const end = impl_.cs_ +
2512  
        impl_.offset(id_query);
2540  
        impl_.offset(id_query);
2513  
    if(impl_.nseg_ == 1)
2541  
    if(impl_.nseg_ == 1)
2514  
        return core::string_view(
2542  
        return core::string_view(
2515  
            p0, end - p0);
2543  
            p0, end - p0);
2516  
    auto p = p0;
2544  
    auto p = p0;
2517  
    while(*p != '/')
2545  
    while(*p != '/')
2518  
        ++p;
2546  
        ++p;
2519  
    BOOST_ASSERT(p < end);
2547  
    BOOST_ASSERT(p < end);
2520  
    return core::string_view(p0, p - p0);
2548  
    return core::string_view(p0, p - p0);
2521  
}
2549  
}
2522  

2550  

2523  
detail::segments_iter_impl
2551  
detail::segments_iter_impl
2524  
url_base::
2552  
url_base::
2525  
edit_segments(
2553  
edit_segments(
2526  
    detail::segments_iter_impl const& it0,
2554  
    detail::segments_iter_impl const& it0,
2527  
    detail::segments_iter_impl const& it1,
2555  
    detail::segments_iter_impl const& it1,
2528  
    detail::any_segments_iter&& src,
2556  
    detail::any_segments_iter&& src,
2529  
    // -1 = preserve
2557  
    // -1 = preserve
2530  
    //  0 = make relative (can fail)
2558  
    //  0 = make relative (can fail)
2531  
    //  1 = make absolute
2559  
    //  1 = make absolute
2532  
    int absolute)
2560  
    int absolute)
2533  
{
2561  
{
2534  
    // Iterator doesn't belong to this url
2562  
    // Iterator doesn't belong to this url
2535  
    BOOST_ASSERT(it0.ref.alias_of(impl_));
2563  
    BOOST_ASSERT(it0.ref.alias_of(impl_));
2536  

2564  

2537  
    // Iterator doesn't belong to this url
2565  
    // Iterator doesn't belong to this url
2538  
    BOOST_ASSERT(it1.ref.alias_of(impl_));
2566  
    BOOST_ASSERT(it1.ref.alias_of(impl_));
2539  

2567  

2540  
    // Iterator is in the wrong order
2568  
    // Iterator is in the wrong order
2541  
    BOOST_ASSERT(it0.index <= it1.index);
2569  
    BOOST_ASSERT(it0.index <= it1.index);
2542  

2570  

2543  
    // Iterator is out of range
2571  
    // Iterator is out of range
2544  
    BOOST_ASSERT(it0.index <= impl_.nseg_);
2572  
    BOOST_ASSERT(it0.index <= impl_.nseg_);
2545  
    BOOST_ASSERT(it0.pos <= impl_.len(id_path));
2573  
    BOOST_ASSERT(it0.pos <= impl_.len(id_path));
2546  

2574  

2547  
    // Iterator is out of range
2575  
    // Iterator is out of range
2548  
    BOOST_ASSERT(it1.index <= impl_.nseg_);
2576  
    BOOST_ASSERT(it1.index <= impl_.nseg_);
2549  
    BOOST_ASSERT(it1.pos <= impl_.len(id_path));
2577  
    BOOST_ASSERT(it1.pos <= impl_.len(id_path));
2550  

2578  

2551  
//------------------------------------------------
2579  
//------------------------------------------------
2552  
//
2580  
//
2553  
//  Calculate output prefix
2581  
//  Calculate output prefix
2554  
//
2582  
//
2555  
//  0 = ""
2583  
//  0 = ""
2556  
//  1 = "/"
2584  
//  1 = "/"
2557  
//  2 = "./"
2585  
//  2 = "./"
2558  
//  3 = "/./"
2586  
//  3 = "/./"
2559  
//
2587  
//
2560  
    bool const is_abs = is_path_absolute();
2588  
    bool const is_abs = is_path_absolute();
2561  
    if(has_authority())
2589  
    if(has_authority())
2562  
    {
2590  
    {
2563  
        // Check if the new
2591  
        // Check if the new
2564  
        // path would be empty
2592  
        // path would be empty
2565  
        if( src.fast_nseg == 0 &&
2593  
        if( src.fast_nseg == 0 &&
2566  
            it0.index == 0 &&
2594  
            it0.index == 0 &&
2567  
            it1.index == impl_.nseg_)
2595  
            it1.index == impl_.nseg_)
2568  
        {
2596  
        {
2569  
            // VFALCO we don't have
2597  
            // VFALCO we don't have
2570  
            // access to nchar this early
2598  
            // access to nchar this early
2571  
            //
2599  
            //
2572  
            //BOOST_ASSERT(nchar == 0);
2600  
            //BOOST_ASSERT(nchar == 0);
2573  
            absolute = 0;
2601  
            absolute = 0;
2574  
        }
2602  
        }
2575  
        else
2603  
        else
2576  
        {
2604  
        {
2577  
            // prefix "/" required
2605  
            // prefix "/" required
2578  
            absolute = 1;
2606  
            absolute = 1;
2579  
        }
2607  
        }
2580  
    }
2608  
    }
2581  
    else if(absolute < 0)
2609  
    else if(absolute < 0)
2582  
    {
2610  
    {
2583  
        absolute = is_abs; // preserve
2611  
        absolute = is_abs; // preserve
2584  
    }
2612  
    }
2585  
    auto const path_pos = impl_.offset(id_path);
2613  
    auto const path_pos = impl_.offset(id_path);
2586  

2614  

2587  
    std::size_t nchar = 0;
2615  
    std::size_t nchar = 0;
2588  
    std::size_t prefix = 0;
2616  
    std::size_t prefix = 0;
2589  
    bool encode_colons = false;
2617  
    bool encode_colons = false;
2590  
    bool cp_src_prefix = false;
2618  
    bool cp_src_prefix = false;
2591  
    if(it0.index > 0)
2619  
    if(it0.index > 0)
2592  
    {
2620  
    {
2593  
        // first segment unchanged
2621  
        // first segment unchanged
2594  
        prefix = src.fast_nseg > 0;
2622  
        prefix = src.fast_nseg > 0;
2595  
    }
2623  
    }
2596  
    else if(src.fast_nseg > 0)
2624  
    else if(src.fast_nseg > 0)
2597  
    {
2625  
    {
2598  
        // first segment from src
2626  
        // first segment from src
2599  
        if(! src.front.empty())
2627  
        if(! src.front.empty())
2600  
        {
2628  
        {
2601  
            if( src.front == "." &&
2629  
            if( src.front == "." &&
2602  
                    src.fast_nseg > 1)
2630  
                    src.fast_nseg > 1)
2603  
                if (src.s.empty())
2631  
                if (src.s.empty())
2604  
                {
2632  
                {
2605  
                    // if front is ".", we need the extra "." in the prefix
2633  
                    // if front is ".", we need the extra "." in the prefix
2606  
                    // which will maintain the invariant that segments represent
2634  
                    // which will maintain the invariant that segments represent
2607  
                    // {"."}
2635  
                    // {"."}
2608  
                    prefix = 2 + absolute;
2636  
                    prefix = 2 + absolute;
2609  
                }
2637  
                }
2610  
                else
2638  
                else
2611  
                {
2639  
                {
2612  
                    // if the "." prefix is explicitly required from set_path
2640  
                    // if the "." prefix is explicitly required from set_path
2613  
                    // we do not include an extra "." segment
2641  
                    // we do not include an extra "." segment
2614  
                    prefix = absolute;
2642  
                    prefix = absolute;
2615  
                    cp_src_prefix = true;
2643  
                    cp_src_prefix = true;
2616  
                }
2644  
                }
2617  
            else if(absolute)
2645  
            else if(absolute)
2618  
                prefix = 1;
2646  
                prefix = 1;
2619  
            else if(has_scheme() ||
2647  
            else if(has_scheme() ||
2620  
                    ! src.front.contains(':'))
2648  
                    ! src.front.contains(':'))
2621  
                prefix = 0;
2649  
                prefix = 0;
2622  
            else
2650  
            else
2623  
            {
2651  
            {
2624  
                prefix = 0;
2652  
                prefix = 0;
2625  
                encode_colons = true;
2653  
                encode_colons = true;
2626  
            }
2654  
            }
2627  
        }
2655  
        }
2628  
        else
2656  
        else
2629  
        {
2657  
        {
2630  
            prefix = 2 + absolute;
2658  
            prefix = 2 + absolute;
2631  
        }
2659  
        }
2632  
    }
2660  
    }
2633  
    else
2661  
    else
2634  
    {
2662  
    {
2635  
        // first segment from it1
2663  
        // first segment from it1
2636  
        auto const p =
2664  
        auto const p =
2637  
            impl_.cs_ + path_pos + it1.pos;
2665  
            impl_.cs_ + path_pos + it1.pos;
2638  
        switch(impl_.cs_ +
2666  
        switch(impl_.cs_ +
2639  
            impl_.offset(id_query) - p)
2667  
            impl_.offset(id_query) - p)
2640  
        {
2668  
        {
2641  
        case 0:
2669  
        case 0:
2642  
            // points to end
2670  
            // points to end
2643  
            prefix = absolute;
2671  
            prefix = absolute;
2644  
            break;
2672  
            break;
2645  
        default:
2673  
        default:
2646  
            BOOST_ASSERT(*p == '/');
2674  
            BOOST_ASSERT(*p == '/');
2647  
            if(p[1] != '/')
2675  
            if(p[1] != '/')
2648  
            {
2676  
            {
2649  
                if(absolute)
2677  
                if(absolute)
2650  
                    prefix = 1;
2678  
                    prefix = 1;
2651  
                else if(has_scheme() ||
2679  
                else if(has_scheme() ||
2652  
                        ! it1.dereference().contains(':'))
2680  
                        ! it1.dereference().contains(':'))
2653  
                    prefix = 0;
2681  
                    prefix = 0;
2654  
                else
2682  
                else
2655  
                    prefix = 2;
2683  
                    prefix = 2;
2656  
                break;
2684  
                break;
2657  
            }
2685  
            }
2658  
            // empty
2686  
            // empty
2659  
            BOOST_FALLTHROUGH;
2687  
            BOOST_FALLTHROUGH;
2660  
        case 1:
2688  
        case 1:
2661  
            // empty
2689  
            // empty
2662  
            BOOST_ASSERT(*p == '/');
2690  
            BOOST_ASSERT(*p == '/');
2663  
            prefix = 2 + absolute;
2691  
            prefix = 2 + absolute;
2664  
            break;
2692  
            break;
2665  
        }
2693  
        }
2666  
    }
2694  
    }
2667  

2695  

2668  
//  append '/' to new segs
2696  
//  append '/' to new segs
2669  
//  if inserting at front.
2697  
//  if inserting at front.
2670  
    std::size_t const suffix =
2698  
    std::size_t const suffix =
2671  
        it1.index == 0 &&
2699  
        it1.index == 0 &&
2672  
        impl_.nseg_ > 0 &&
2700  
        impl_.nseg_ > 0 &&
2673  
        src.fast_nseg > 0;
2701  
        src.fast_nseg > 0;
2674  

2702  

2675  
//------------------------------------------------
2703  
//------------------------------------------------
2676  
//
2704  
//
2677  
//  Measure the number of encoded characters
2705  
//  Measure the number of encoded characters
2678  
//  of output, and the number of inserted
2706  
//  of output, and the number of inserted
2679  
//  segments including internal separators.
2707  
//  segments including internal separators.
2680  
//
2708  
//
2681  
    src.encode_colons = encode_colons;
2709  
    src.encode_colons = encode_colons;
2682  
    std::size_t nseg = 0;
2710  
    std::size_t nseg = 0;
2683  
    if(src.measure(nchar))
2711  
    if(src.measure(nchar))
2684  
    {
2712  
    {
2685  
        src.encode_colons = false;
2713  
        src.encode_colons = false;
2686  
        for(;;)
2714  
        for(;;)
2687  
        {
2715  
        {
2688  
            ++nseg;
2716  
            ++nseg;
2689  
            if(! src.measure(nchar))
2717  
            if(! src.measure(nchar))
2690  
                break;
2718  
                break;
2691  
            ++nchar;
2719  
            ++nchar;
2692  
        }
2720  
        }
2693  
    }
2721  
    }
2694  

2722  

2695  
    switch(src.fast_nseg)
2723  
    switch(src.fast_nseg)
2696  
    {
2724  
    {
2697  
    case 0:
2725  
    case 0:
2698  
        BOOST_ASSERT(nseg == 0);
2726  
        BOOST_ASSERT(nseg == 0);
2699  
        break;
2727  
        break;
2700  
    case 1:
2728  
    case 1:
2701  
        BOOST_ASSERT(nseg == 1);
2729  
        BOOST_ASSERT(nseg == 1);
2702  
        break;
2730  
        break;
2703  
    case 2:
2731  
    case 2:
2704  
        BOOST_ASSERT(nseg >= 2);
2732  
        BOOST_ASSERT(nseg >= 2);
2705  
        break;
2733  
        break;
2706  
    }
2734  
    }
2707  

2735  

2708  
//------------------------------------------------
2736  
//------------------------------------------------
2709  
//
2737  
//
2710  
//  Calculate [pos0, pos1) to remove
2738  
//  Calculate [pos0, pos1) to remove
2711  
//
2739  
//
2712  
    auto pos0 = it0.pos;
2740  
    auto pos0 = it0.pos;
2713  
    if(it0.index == 0)
2741  
    if(it0.index == 0)
2714  
    {
2742  
    {
2715  
        // patch pos for prefix
2743  
        // patch pos for prefix
2716  
        pos0 = 0;
2744  
        pos0 = 0;
2717  
    }
2745  
    }
2718  
    auto pos1 = it1.pos;
2746  
    auto pos1 = it1.pos;
2719  
    if(it1.index == 0)
2747  
    if(it1.index == 0)
2720  
    {
2748  
    {
2721  
        // patch pos for prefix
2749  
        // patch pos for prefix
2722  
        pos1 = detail::path_prefix(
2750  
        pos1 = detail::path_prefix(
2723  
            impl_.get(id_path));
2751  
            impl_.get(id_path));
2724  
    }
2752  
    }
2725  
    else if(
2753  
    else if(
2726  
        it0.index == 0 &&
2754  
        it0.index == 0 &&
2727  
        it1.index < impl_.nseg_ &&
2755  
        it1.index < impl_.nseg_ &&
2728  
        nseg == 0)
2756  
        nseg == 0)
2729  
    {
2757  
    {
2730  
        // Remove the slash from segment it1
2758  
        // Remove the slash from segment it1
2731  
        // if it is becoming the new first
2759  
        // if it is becoming the new first
2732  
        // segment.
2760  
        // segment.
2733  
        ++pos1;
2761  
        ++pos1;
2734  
    }
2762  
    }
2735  
    // calc decoded size of old range
2763  
    // calc decoded size of old range
2736  
    auto const dn0 =
2764  
    auto const dn0 =
2737  
        detail::decode_bytes_unsafe(
2765  
        detail::decode_bytes_unsafe(
2738  
            core::string_view(
2766  
            core::string_view(
2739  
                impl_.cs_ +
2767  
                impl_.cs_ +
2740  
                    impl_.offset(id_path) +
2768  
                    impl_.offset(id_path) +
2741  
                    pos0,
2769  
                    pos0,
2742  
                pos1 - pos0));
2770  
                pos1 - pos0));
2743  

2771  

2744  
//------------------------------------------------
2772  
//------------------------------------------------
2745  
//
2773  
//
2746  
//  Resize
2774  
//  Resize
2747  
//
2775  
//
2748  
    op_t op(*this, &src.s);
2776  
    op_t op(*this, &src.s);
2749  
    char* dest;
2777  
    char* dest;
2750  
    char const* end;
2778  
    char const* end;
2751  
    {
2779  
    {
2752  
        auto const nremove = pos1 - pos0;
2780  
        auto const nremove = pos1 - pos0;
2753  
        // check overflow
2781  
        // check overflow
2754  
        if( nchar <= max_size() && (
2782  
        if( nchar <= max_size() && (
2755  
            prefix + suffix <=
2783  
            prefix + suffix <=
2756  
                max_size() - nchar))
2784  
                max_size() - nchar))
2757  
        {
2785  
        {
2758  
            nchar = prefix + nchar + suffix;
2786  
            nchar = prefix + nchar + suffix;
2759  
            if( nchar <= nremove ||
2787  
            if( nchar <= nremove ||
2760  
                nchar - nremove <=
2788  
                nchar - nremove <=
2761  
                    max_size() - size())
2789  
                    max_size() - size())
2762  
                goto ok;
2790  
                goto ok;
2763  
        }
2791  
        }
2764  
        // too large
2792  
        // too large
2765  
        detail::throw_length_error();
2793  
        detail::throw_length_error();
2766  
    ok:
2794  
    ok:
2767  
        auto const new_size =
2795  
        auto const new_size =
2768  
            size() + nchar - nremove;
2796  
            size() + nchar - nremove;
2769  
        reserve_impl(new_size, op);
2797  
        reserve_impl(new_size, op);
2770  
        dest = s_ + path_pos + pos0;
2798  
        dest = s_ + path_pos + pos0;
2771  
        op.move(
2799  
        op.move(
2772  
            dest + nchar,
2800  
            dest + nchar,
2773  
            s_ + path_pos + pos1,
2801  
            s_ + path_pos + pos1,
2774  
            size() - path_pos - pos1);
2802  
            size() - path_pos - pos1);
2775  
        impl_.set_size(
2803  
        impl_.set_size(
2776  
            id_path,
2804  
            id_path,
2777  
            impl_.len(id_path) + nchar - nremove);
2805  
            impl_.len(id_path) + nchar - nremove);
2778  
        BOOST_ASSERT(size() == new_size);
2806  
        BOOST_ASSERT(size() == new_size);
2779  
        end = dest + nchar;
2807  
        end = dest + nchar;
2780 -
        impl_.nseg_ = impl_.nseg_ + nseg - (
2808 +
        auto const nseg1 =
2781 -
            it1.index - it0.index) - cp_src_prefix;
2809 +
            static_cast<std::ptrdiff_t>(impl_.nseg_) +
 
2810 +
            static_cast<std::ptrdiff_t>(nseg) -
 
2811 +
            static_cast<std::ptrdiff_t>(it1.index) +
 
2812 +
            static_cast<std::ptrdiff_t>(it0.index) -
 
2813 +
            static_cast<std::ptrdiff_t>(cp_src_prefix);
 
2814 +
        BOOST_ASSERT(nseg1 >= 0);
 
2815 +
        impl_.nseg_ = detail::to_size_type(nseg1);
2782  
        if(s_)
2816  
        if(s_)
2783  
            s_[size()] = '\0';
2817  
            s_[size()] = '\0';
2784  
    }
2818  
    }
2785  

2819  

2786  
//------------------------------------------------
2820  
//------------------------------------------------
2787  
//
2821  
//
2788  
//  Output segments and internal separators:
2822  
//  Output segments and internal separators:
2789  
//
2823  
//
2790  
//  prefix [ segment [ '/' segment ] ] suffix
2824  
//  prefix [ segment [ '/' segment ] ] suffix
2791  
//
2825  
//
2792  
    auto const dest0 = dest;
2826  
    auto const dest0 = dest;
2793  
    switch(prefix)
2827  
    switch(prefix)
2794  
    {
2828  
    {
2795  
    case 3:
2829  
    case 3:
2796  
        *dest++ = '/';
2830  
        *dest++ = '/';
2797  
        *dest++ = '.';
2831  
        *dest++ = '.';
2798  
        *dest++ = '/';
2832  
        *dest++ = '/';
2799  
        break;
2833  
        break;
2800  
    case 2:
2834  
    case 2:
2801  
        *dest++ = '.';
2835  
        *dest++ = '.';
2802  
        BOOST_FALLTHROUGH;
2836  
        BOOST_FALLTHROUGH;
2803  
    case 1:
2837  
    case 1:
2804  
        *dest++ = '/';
2838  
        *dest++ = '/';
2805  
        break;
2839  
        break;
2806  
    default:
2840  
    default:
2807  
        break;
2841  
        break;
2808  
    }
2842  
    }
2809  
    src.rewind();
2843  
    src.rewind();
2810  
    if(nseg > 0)
2844  
    if(nseg > 0)
2811  
    {
2845  
    {
2812  
        src.encode_colons = encode_colons;
2846  
        src.encode_colons = encode_colons;
2813  
        for(;;)
2847  
        for(;;)
2814  
        {
2848  
        {
2815  
            src.copy(dest, end);
2849  
            src.copy(dest, end);
2816  
            if(--nseg == 0)
2850  
            if(--nseg == 0)
2817  
                break;
2851  
                break;
2818  
            *dest++ = '/';
2852  
            *dest++ = '/';
2819  
            src.encode_colons = false;
2853  
            src.encode_colons = false;
2820  
        }
2854  
        }
2821  
        if(suffix)
2855  
        if(suffix)
2822  
            *dest++ = '/';
2856  
            *dest++ = '/';
2823  
    }
2857  
    }
2824  
    BOOST_ASSERT(dest == dest0 + nchar);
2858  
    BOOST_ASSERT(dest == dest0 + nchar);
2825  

2859  

2826  
    // calc decoded size of new range,
2860  
    // calc decoded size of new range,
2827  
    auto const dn =
2861  
    auto const dn =
2828  
        detail::decode_bytes_unsafe(
2862  
        detail::decode_bytes_unsafe(
2829  
            core::string_view(dest0, dest - dest0));
2863  
            core::string_view(dest0, dest - dest0));
2830 -
    impl_.decoded_[id_path] += dn - dn0;
2864 +
    if(dn >= dn0)
 
2865 +
        impl_.decoded_[id_path] +=
 
2866 +
            detail::to_size_type(dn - dn0);
 
2867 +
    else
 
2868 +
        impl_.decoded_[id_path] -=
 
2869 +
            detail::to_size_type(dn0 - dn);
2831  

2870  

2832  
    return detail::segments_iter_impl(
2871  
    return detail::segments_iter_impl(
2833  
        impl_, pos0, it0.index);
2872  
        impl_, pos0, it0.index);
2834  
}
2873  
}
2835  

2874  

2836  
//------------------------------------------------
2875  
//------------------------------------------------
2837  

2876  

2838  
auto
2877  
auto
2839  
url_base::
2878  
url_base::
2840  
edit_params(
2879  
edit_params(
2841  
    detail::params_iter_impl const& it0,
2880  
    detail::params_iter_impl const& it0,
2842  
    detail::params_iter_impl const& it1,
2881  
    detail::params_iter_impl const& it1,
2843  
    detail::any_params_iter&& src) ->
2882  
    detail::any_params_iter&& src) ->
2844  
        detail::params_iter_impl
2883  
        detail::params_iter_impl
2845  
{
2884  
{
2846  
    auto pos0 = impl_.offset(id_query);
2885  
    auto pos0 = impl_.offset(id_query);
2847  
    auto pos1 = pos0 + it1.pos;
2886  
    auto pos1 = pos0 + it1.pos;
2848  
    pos0 = pos0 + it0.pos;
2887  
    pos0 = pos0 + it0.pos;
2849  

2888  

2850  
    // Iterators belong to this url
2889  
    // Iterators belong to this url
2851  
    BOOST_ASSERT(it0.ref.alias_of(impl_));
2890  
    BOOST_ASSERT(it0.ref.alias_of(impl_));
2852  
    BOOST_ASSERT(it1.ref.alias_of(impl_));
2891  
    BOOST_ASSERT(it1.ref.alias_of(impl_));
2853  

2892  

2854  
    // Iterators is in the right order
2893  
    // Iterators is in the right order
2855  
    BOOST_ASSERT(it0.index <= it1.index);
2894  
    BOOST_ASSERT(it0.index <= it1.index);
2856  

2895  

2857  
    // Iterators are within range
2896  
    // Iterators are within range
2858  
    BOOST_ASSERT(it0.index <= impl_.nparam_);
2897  
    BOOST_ASSERT(it0.index <= impl_.nparam_);
2859  
    BOOST_ASSERT(pos0 <= impl_.offset(id_frag));
2898  
    BOOST_ASSERT(pos0 <= impl_.offset(id_frag));
2860  
    BOOST_ASSERT(it1.index <= impl_.nparam_);
2899  
    BOOST_ASSERT(it1.index <= impl_.nparam_);
2861  
    BOOST_ASSERT(pos1 <= impl_.offset(id_frag));
2900  
    BOOST_ASSERT(pos1 <= impl_.offset(id_frag));
2862  

2901  

2863  
    // calc decoded size of old range,
2902  
    // calc decoded size of old range,
2864  
    // minus one if '?' or '&' prefixed
2903  
    // minus one if '?' or '&' prefixed
2865 -
    auto const dn0 =
2904 +
    auto dn0 =
2866 -
        detail::decode_bytes_unsafe(
2905 +
        static_cast<std::ptrdiff_t>(
2867 -
            core::string_view(
2906 +
            detail::decode_bytes_unsafe(
2868 -
                impl_.cs_ + pos0,
2907 +
                core::string_view(
2869 -
                pos1 - pos0)) - (
2908 +
                    impl_.cs_ + pos0,
2870 -
                    impl_.len(id_query) > 0);
2909 +
                    pos1 - pos0)));
 
2910 +
    if(impl_.len(id_query) > 0)
 
2911 +
        dn0 -= 1;
 
2912 +
    if(dn0 < 0)
 
2913 +
        dn0 = 0;
2871  

2914  

2872  
//------------------------------------------------
2915  
//------------------------------------------------
2873  
//
2916  
//
2874  
//  Measure the number of encoded characters
2917  
//  Measure the number of encoded characters
2875  
//  of output, and the number of inserted
2918  
//  of output, and the number of inserted
2876  
//  segments including internal separators.
2919  
//  segments including internal separators.
2877  
//
2920  
//
2878  

2921  

2879  
    std::size_t nchar = 0;
2922  
    std::size_t nchar = 0;
2880  
    std::size_t nparam = 0;
2923  
    std::size_t nparam = 0;
2881  
    if(src.measure(nchar))
2924  
    if(src.measure(nchar))
2882  
    {
2925  
    {
2883  
        ++nchar; // for '?' or '&'
2926  
        ++nchar; // for '?' or '&'
2884  
        for(;;)
2927  
        for(;;)
2885  
        {
2928  
        {
2886  
            ++nparam;
2929  
            ++nparam;
2887  
            if(! src.measure(nchar))
2930  
            if(! src.measure(nchar))
2888  
                break;
2931  
                break;
2889  
            ++nchar; // for '&'
2932  
            ++nchar; // for '&'
2890  
        }
2933  
        }
2891  
    }
2934  
    }
2892  

2935  

2893  
//------------------------------------------------
2936  
//------------------------------------------------
2894  
//
2937  
//
2895  
//  Resize
2938  
//  Resize
2896  
//
2939  
//
2897  
    op_t op(*this, &src.s0, &src.s1);
2940  
    op_t op(*this, &src.s0, &src.s1);
2898  
    char* dest;
2941  
    char* dest;
2899  
    char const* end;
2942  
    char const* end;
2900  
    {
2943  
    {
2901  
        auto const nremove = pos1 - pos0;
2944  
        auto const nremove = pos1 - pos0;
2902  
        // check overflow
2945  
        // check overflow
2903  
        if( nchar > nremove &&
2946  
        if( nchar > nremove &&
2904  
            nchar - nremove >
2947  
            nchar - nremove >
2905  
                max_size() - size())
2948  
                max_size() - size())
2906  
        {
2949  
        {
2907  
            // too large
2950  
            // too large
2908  
            detail::throw_length_error();
2951  
            detail::throw_length_error();
2909  
        }
2952  
        }
2910  
        auto const nparam1 =
2953  
        auto const nparam1 =
2911 -
            impl_.nparam_ + nparam - (
2954 +
            static_cast<std::ptrdiff_t>(impl_.nparam_) +
2912 -
                it1.index - it0.index);
2955 +
            static_cast<std::ptrdiff_t>(nparam) -
 
2956 +
            static_cast<std::ptrdiff_t>(it1.index) +
 
2957 +
            static_cast<std::ptrdiff_t>(it0.index);
 
2958 +
        BOOST_ASSERT(nparam1 >= 0);
2913  
        reserve_impl(size() + nchar - nremove, op);
2959  
        reserve_impl(size() + nchar - nremove, op);
2914  
        dest = s_ + pos0;
2960  
        dest = s_ + pos0;
2915  
        end = dest + nchar;
2961  
        end = dest + nchar;
2916  
        if(impl_.nparam_ > 0)
2962  
        if(impl_.nparam_ > 0)
2917  
        {
2963  
        {
2918  
            // needed when we move
2964  
            // needed when we move
2919  
            // the beginning of the query
2965  
            // the beginning of the query
2920  
            s_[impl_.offset(id_query)] = '&';
2966  
            s_[impl_.offset(id_query)] = '&';
2921  
        }
2967  
        }
2922  
        op.move(
2968  
        op.move(
2923  
            dest + nchar,
2969  
            dest + nchar,
2924  
            impl_.cs_ + pos1,
2970  
            impl_.cs_ + pos1,
2925  
            size() - pos1);
2971  
            size() - pos1);
2926  
        impl_.set_size(
2972  
        impl_.set_size(
2927  
            id_query,
2973  
            id_query,
2928  
            impl_.len(id_query) +
2974  
            impl_.len(id_query) +
2929  
                nchar - nremove);
2975  
                nchar - nremove);
2930 -
        impl_.nparam_ = nparam1;
2976 +
        impl_.nparam_ =
 
2977 +
            detail::to_size_type(nparam1);
2931  
        if(nparam1 > 0)
2978  
        if(nparam1 > 0)
2932  
        {
2979  
        {
2933  
            // needed when we erase
2980  
            // needed when we erase
2934  
            // the beginning of the query
2981  
            // the beginning of the query
2935  
            s_[impl_.offset(id_query)] = '?';
2982  
            s_[impl_.offset(id_query)] = '?';
2936  
        }
2983  
        }
2937  
        if(s_)
2984  
        if(s_)
2938  
            s_[size()] = '\0';
2985  
            s_[size()] = '\0';
2939  
    }
2986  
    }
2940  
    auto const dest0 = dest;
2987  
    auto const dest0 = dest;
2941  

2988  

2942  
//------------------------------------------------
2989  
//------------------------------------------------
2943  
//
2990  
//
2944  
//  Output params and internal separators:
2991  
//  Output params and internal separators:
2945  
//
2992  
//
2946  
//  [ '?' param ] [ '&' param ]
2993  
//  [ '?' param ] [ '&' param ]
2947  
//
2994  
//
2948  
    if(nparam > 0)
2995  
    if(nparam > 0)
2949  
    {
2996  
    {
2950  
        if(it0.index == 0)
2997  
        if(it0.index == 0)
2951  
            *dest++ = '?';
2998  
            *dest++ = '?';
2952  
        else
2999  
        else
2953  
            *dest++ = '&';
3000  
            *dest++ = '&';
2954  
        src.rewind();
3001  
        src.rewind();
2955  
        for(;;)
3002  
        for(;;)
2956  
        {
3003  
        {
2957  
            src.copy(dest, end);
3004  
            src.copy(dest, end);
2958  
            if(--nparam == 0)
3005  
            if(--nparam == 0)
2959  
                break;
3006  
                break;
2960  
            *dest++ = '&';
3007  
            *dest++ = '&';
2961  
        }
3008  
        }
2962  
    }
3009  
    }
2963  

3010  

2964  
    // calc decoded size of new range,
3011  
    // calc decoded size of new range,
2965  
    // minus one if '?' or '&' prefixed
3012  
    // minus one if '?' or '&' prefixed
2966 -
    auto const dn =
3013 +
    auto dn =
2967 -
        detail::decode_bytes_unsafe(
3014 +
        static_cast<std::ptrdiff_t>(
2968 -
            core::string_view(dest0, dest - dest0)) - (
3015 +
            detail::decode_bytes_unsafe(
2969 -
                impl_.len(id_query) > 0);
3016 +
                core::string_view(dest0, dest - dest0)));
 
3017 +
    if(impl_.len(id_query) > 0)
 
3018 +
        dn -= 1;
 
3019 +
    if(dn < 0)
 
3020 +
        dn = 0;
2970  

3021  

2971 -
    impl_.decoded_[id_query] += (dn - dn0);
3022 +
    if(dn >= dn0)
 
3023 +
        impl_.decoded_[id_query] +=
 
3024 +
            detail::to_size_type(dn - dn0);
 
3025 +
    else
 
3026 +
        impl_.decoded_[id_query] -=
 
3027 +
            detail::to_size_type(dn0 - dn);
2972  

3028  

2973  
    return detail::params_iter_impl(
3029  
    return detail::params_iter_impl(
2974  
        impl_,
3030  
        impl_,
2975  
        pos0 - impl_.offset_[id_query],
3031  
        pos0 - impl_.offset_[id_query],
2976  
        it0.index);
3032  
        it0.index);
2977  
}
3033  
}
2978  

3034  

2979  
//------------------------------------------------
3035  
//------------------------------------------------
2980  

3036  

2981  
void
3037  
void
2982  
url_base::
3038  
url_base::
2983  
decoded_to_lower_impl(int id) noexcept
3039  
decoded_to_lower_impl(int id) noexcept
2984  
{
3040  
{
2985  
    char* it = s_ + impl_.offset(id);
3041  
    char* it = s_ + impl_.offset(id);
2986  
    char const* const end = s_ + impl_.offset(id + 1);
3042  
    char const* const end = s_ + impl_.offset(id + 1);
2987  
    while(it < end)
3043  
    while(it < end)
2988  
    {
3044  
    {
2989  
        if (*it != '%')
3045  
        if (*it != '%')
2990  
        {
3046  
        {
2991  
            *it = grammar::to_lower(
3047  
            *it = grammar::to_lower(
2992  
                *it);
3048  
                *it);
2993  
            ++it;
3049  
            ++it;
2994  
            continue;
3050  
            continue;
2995  
        }
3051  
        }
2996  
        it += 3;
3052  
        it += 3;
2997  
    }
3053  
    }
2998  
}
3054  
}
2999  

3055  

3000  
void
3056  
void
3001  
url_base::
3057  
url_base::
3002  
to_lower_impl(int id) noexcept
3058  
to_lower_impl(int id) noexcept
3003  
{
3059  
{
3004  
    char* it = s_ + impl_.offset(id);
3060  
    char* it = s_ + impl_.offset(id);
3005  
    char const* const end = s_ + impl_.offset(id + 1);
3061  
    char const* const end = s_ + impl_.offset(id + 1);
3006  
    while(it < end)
3062  
    while(it < end)
3007  
    {
3063  
    {
3008  
        *it = grammar::to_lower(
3064  
        *it = grammar::to_lower(
3009  
            *it);
3065  
            *it);
3010  
        ++it;
3066  
        ++it;
3011  
    }
3067  
    }
3012  
}
3068  
}
3013  

3069  

3014  
} // urls
3070  
} // urls
3015  
} // boost
3071  
} // boost