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

 
10  

10  

11 -
#include "path.hpp"
 
12  
#include <boost/url/detail/config.hpp>
11  
#include <boost/url/detail/config.hpp>
13 -
#include <boost/url/authority_view.hpp>
 
14 -
#include <boost/assert.hpp>
 
15 -
#include <cstring>
 
16  
#include <boost/url/detail/url_impl.hpp>
12  
#include <boost/url/detail/url_impl.hpp>
17  

13  

18  
namespace boost {
14  
namespace boost {
19  
namespace urls {
15  
namespace urls {
20  
namespace detail {
16  
namespace detail {
21 -
#if defined(__GNUC__) && ! defined(__clang__) && defined(__MINGW32__)
 
22 -
#pragma GCC diagnostic push
 
23 -
#pragma GCC diagnostic ignored "-Warray-bounds"
 
24 -
#endif
 
25 -

 
26 -
//------------------------------------------------
 
27 -
//
 
28 -
// url_impl
 
29 -
//
 
30 -
//------------------------------------------------
 
31 -

 
32 -
void
 
33 -
url_impl::
 
34 -
apply_scheme(
 
35 -
    core::string_view s) noexcept
 
36 -
{
 
37 -
    scheme_ = string_to_scheme(s);
 
38 -
    set_size(id_scheme, s.size() + 1);
 
39 -
}
 
40 -

 
41 -
void
 
42 -
url_impl::
 
43 -
apply_userinfo(
 
44 -
    pct_string_view const& user,
 
45 -
    pct_string_view const* pass) noexcept
 
46 -
{
 
47 -
    // this function is for
 
48 -
    // authority_view_rule only
 
49 -
    BOOST_ASSERT(from_ == from::authority);
 
50 -

 
51 -
    // userinfo
 
52 -
    set_size(id_user, user.size());
 
53 -
    decoded_[id_user] =
 
54 -
        detail::to_size_type(
 
55 -
            user.decoded_size());
 
56 -
    if(pass)
 
57 -
    {
 
58 -
        set_size(id_pass,
 
59 -
            pass->size() + 2);
 
60 -
        decoded_[id_pass] =
 
61 -
            detail::to_size_type(
 
62 -
                pass->decoded_size());
 
63 -
    }
 
64 -
    else
 
65 -
    {
 
66 -
        // trailing '@'
 
67 -
        set_size(id_pass, 1 );
 
68 -
    }
 
69 -
}
 
70 -

 
71 -
void
 
72 -
url_impl::
 
73 -
apply_host(
 
74 -
    host_type ht,
 
75 -
    pct_string_view s,
 
76 -
    unsigned char const* addr) noexcept
 
77 -
{
 
78 -
    // this function is for
 
79 -
    // authority_view_rule only
 
80 -
    BOOST_ASSERT(from_ == from::authority);
 
81 -

 
82 -
    // host, port
 
83 -
    host_type_ = ht;
 
84 -
    set_size(id_host, s.size());
 
85 -
    decoded_[id_host] =
 
86 -
        detail::to_size_type(
 
87 -
            s.decoded_size());
 
88 -
    std::memcpy(
 
89 -
        ip_addr_,
 
90 -
        addr,
 
91 -
        sizeof(ip_addr_));
 
92 -
}
 
93 -

 
94 -
void
 
95 -
url_impl::
 
96 -
apply_port(
 
97 -
    core::string_view s,
 
98 -
    unsigned short pn) noexcept
 
99 -
{
 
100 -
    // this function is for
 
101 -
    // authority_view_rule only
 
102 -
    BOOST_ASSERT(from_ == from::authority);
 
103 -

 
104 -
    port_number_ = pn;
 
105 -
    set_size(id_port, 1 + s.size());
 
106 -
}
 
107 -

 
108 -
void
 
109 -
url_impl::
 
110 -
apply_authority(
 
111 -
    authority_view const& a) noexcept
 
112 -
{
 
113 -
    BOOST_ASSERT(from_ != from::authority);
 
114 -

 
115 -
    // userinfo
 
116 -
    set_size(id_user,
 
117 -
        a.u_.len(id_user) +
 
118 -
        (from_ == from::authority ? 0 : 2));
 
119 -
    set_size(id_pass, a.u_.len(id_pass));
 
120 -
    decoded_[id_user] = a.u_.decoded_[id_user];
 
121 -
    decoded_[id_pass] = a.u_.decoded_[id_pass];
 
122 -

 
123 -
    // host, port
 
124 -
    host_type_ = a.u_.host_type_;
 
125 -
    port_number_ = a.u_.port_number_;
 
126 -
    set_size(id_host, a.u_.len(id_host));
 
127 -
    set_size(id_port, a.u_.len(id_port));
 
128 -
    std::memcpy(
 
129 -
        ip_addr_,
 
130 -
        a.u_.ip_addr_,
 
131 -
        sizeof(ip_addr_));
 
132 -
    decoded_[id_host] = a.u_.decoded_[id_host];
 
133 -
}
 
134 -

 
135 -
void
 
136 -
url_impl::
 
137 -
apply_path(
 
138 -
    pct_string_view s,
 
139 -
    std::size_t nseg) noexcept
 
140 -
{
 
141 -
    set_size(id_path, s.size());
 
142 -
    decoded_[id_path] =
 
143 -
        detail::to_size_type(
 
144 -
            s.decoded_size());
 
145 -
    nseg_ = detail::to_size_type(
 
146 -
        detail::path_segments(s, nseg));
 
147 -
}
 
148 -

 
149 -
void
 
150 -
url_impl::
 
151 -
apply_query(
 
152 -
    pct_string_view s,
 
153 -
    std::size_t n) noexcept
 
154 -
{
 
155 -
    nparam_ = detail::to_size_type(n);
 
156 -
    set_size(id_query, 1 + s.size());
 
157 -
    decoded_[id_query] =
 
158 -
        detail::to_size_type(
 
159 -
            s.decoded_size());
 
160 -
}
 
161 -

 
162 -
void
 
163 -
url_impl::
 
164 -
apply_frag(
 
165 -
    pct_string_view s) noexcept
 
166 -
{
 
167 -
    set_size(id_frag, s.size() + 1);
 
168 -
    decoded_[id_frag] =
 
169 -
        detail::to_size_type(
 
170 -
            s.decoded_size());
 
171 -
}
 
172 -

 
173 -
// return length of [first, last)
 
174 -
auto
 
175 -
url_impl::
 
176 -
len(
 
177 -
    int first,
 
178 -
    int last) const noexcept ->
 
179 -
        std::size_t
 
180 -
{
 
181 -
    BOOST_ASSERT(first <= last);
 
182 -
    BOOST_ASSERT(last <= id_end);
 
183 -
    return offset(last) - offset(first);
 
184 -
}
 
185 -

 
186 -
// return length of part
 
187 -
auto
 
188 -
url_impl::
 
189 -
len(int id) const noexcept ->
 
190 -
    std::size_t
 
191 -
{
 
192 -
    return id == id_end
 
193 -
        ? zero_
 
194 -
        : ( offset(id + 1) -
 
195 -
            offset(id) );
 
196 -
}
 
197 -

 
198 -
// return offset of id
 
199 -
auto
 
200 -
url_impl::
 
201 -
offset(int id) const noexcept ->
 
202 -
    std::size_t
 
203 -
{
 
204 -
    return
 
205 -
        id == id_scheme
 
206 -
        ? zero_
 
207 -
        : offset_[id];
 
208 -
}
 
209 -

 
210 -
// return id as string
 
211 -
core::string_view
 
212 -
url_impl::
 
213 -
get(int id) const noexcept
 
214 -
{
 
215 -
    return {
 
216 -
        cs_ + offset(id), len(id) };
 
217 -
}
 
218 -

 
219 -
// return [first, last) as string
 
220 -
core::string_view
 
221 -
url_impl::
 
222 -
get(int first,
 
223 -
    int last) const noexcept
 
224 -
{
 
225 -
    return { cs_ + offset(first),
 
226 -
        offset(last) - offset(first) };
 
227 -
}
 
228 -

 
229 -
// return id as pct-string
 
230 -
pct_string_view
 
231 -
url_impl::
 
232 -
pct_get(
 
233 -
    int id) const noexcept
 
234 -
{
 
235 -
    return make_pct_string_view_unsafe(
 
236 -
        cs_ + offset(id),
 
237 -
        len(id),
 
238 -
        decoded_[id]);
 
239 -
}
 
240 -

 
241 -
// return [first, last) as pct-string
 
242 -
pct_string_view
 
243 -
url_impl::
 
244 -
pct_get(
 
245 -
    int first,
 
246 -
    int last) const noexcept
 
247 -
{
 
248 -
    auto const pos = offset(first);
 
249 -
    std::size_t n = 0;
 
250 -
    for(auto i = first; i < last;)
 
251 -
        n += decoded_[i++];
 
252 -
    return make_pct_string_view_unsafe(
 
253 -
        cs_ + pos,
 
254 -
        offset(last) - pos,
 
255 -
        n);
 
256 -
}
 
257 -

 
258 -
//------------------------------------------------
 
259 -

 
260 -
// change id to size n
 
261 -
void
 
262 -
url_impl::
 
263 -
set_size(
 
264 -
    int id,
 
265 -
    std::size_t n) noexcept
 
266 -
{
 
267 -
    auto const cur = len(id);
 
268 -
    if(n >= cur)
 
269 -
    {
 
270 -
        auto const d = n - cur;
 
271 -
        for(auto i = id + 1;
 
272 -
            i <= id_end; ++i)
 
273 -
            offset_[i] += detail::to_size_type(d);
 
274 -
        return;
 
275 -
    }
 
276 -
    auto const d = cur - n;
 
277 -
    for(auto i = id + 1;
 
278 -
        i <= id_end; ++i)
 
279 -
        offset_[i] -= detail::to_size_type(d);
 
280 -
}
 
281 -

 
282 -
// trim id to size n,
 
283 -
// moving excess into id+1
 
284 -
void
 
285 -
url_impl::
 
286 -
split(
 
287 -
    int id,
 
288 -
    std::size_t n) noexcept
 
289 -
{
 
290 -
    BOOST_ASSERT(id < id_end - 1);
 
291 -
    //BOOST_ASSERT(n <= len(id));
 
292 -
    offset_[id + 1] = detail::to_size_type(
 
293 -
        offset(id) + n);
 
294 -
}
 
295 -

 
296 -
// add n to [first, last]
 
297 -
void
 
298 -
url_impl::
 
299 -
adjust_right(
 
300 -
    int first,
 
301 -
    int last,
 
302 -
    std::size_t n) noexcept
 
303 -
{
 
304 -
    for(int i = first;
 
305 -
            i <= last; ++i)
 
306 -
        offset_[i] += detail::to_size_type(n);
 
307 -
}
 
308 -

 
309 -
// remove n from [first, last]
 
310 -
void
 
311 -
url_impl::
 
312 -
adjust_left(
 
313 -
    int first,
 
314 -
    int last,
 
315 -
    std::size_t n) noexcept
 
316 -
{
 
317 -
    for(int i = first;
 
318 -
            i <= last; ++i)
 
319 -
        offset_[i] -= detail::to_size_type(n);
 
320 -
}
 
321 -

 
322 -
// set [first, last) offset
 
323 -
void
 
324 -
url_impl::
 
325 -
collapse(
 
326 -
    int first,
 
327 -
    int last,
 
328 -
    std::size_t n) noexcept
 
329 -
{
 
330 -
    for(int i = first + 1;
 
331 -
            i < last; ++i)
 
332 -
        offset_[i] = detail::to_size_type(n);
 
333 -
}
 
334 -

 
335 -

 
336  

17  

337  
//------------------------------------------------
18  
//------------------------------------------------
338  
//
19  
//
339  
// path_ref
20  
// path_ref
340  
//
21  
//
341  
//------------------------------------------------
22  
//------------------------------------------------
342  

23  

343  
path_ref::
24  
path_ref::
 
25 +
path_ref() noexcept = default;
 
26 +

 
27 +
path_ref::
344  
path_ref(
28  
path_ref(
345  
    url_impl const& impl) noexcept
29  
    url_impl const& impl) noexcept
346  
{
30  
{
347  
    if(impl.from_ == url_impl::from::url)
31  
    if(impl.from_ == url_impl::from::url)
348  
    {
32  
    {
349  
        impl_ = &impl;
33  
        impl_ = &impl;
350  
    }
34  
    }
351  
    else
35  
    else
352  
    {
36  
    {
353  
        core::string_view s = impl.get(id_path);
37  
        core::string_view s = impl.get(id_path);
354  
        data_ = s.data();
38  
        data_ = s.data();
355  
        size_ = s.size();
39  
        size_ = s.size();
356  
        nseg_ = impl.nseg_;
40  
        nseg_ = impl.nseg_;
357  
        dn_ = impl.decoded_[id_path];
41  
        dn_ = impl.decoded_[id_path];
358  
    }
42  
    }
359  
}
43  
}
360  

44  

361  
path_ref::
45  
path_ref::
362  
path_ref(
46  
path_ref(
363  
    core::string_view s,
47  
    core::string_view s,
364  
    std::size_t dn,
48  
    std::size_t dn,
365  
    std::size_t nseg) noexcept
49  
    std::size_t nseg) noexcept
366  
    : data_(s.data())
50  
    : data_(s.data())
367  
    , size_(s.size())
51  
    , size_(s.size())
368  
    , nseg_(nseg)
52  
    , nseg_(nseg)
369  
    , dn_(dn)
53  
    , dn_(dn)
370  
{
54  
{
371  
}
55  
}
372  

56  

373  
pct_string_view
57  
pct_string_view
374  
path_ref::
58  
path_ref::
375  
buffer() const noexcept
59  
buffer() const noexcept
376  
{
60  
{
377  
    if(impl_)
61  
    if(impl_)
378  
        return make_pct_string_view_unsafe(
62  
        return make_pct_string_view_unsafe(
379  
            impl_->cs_ +
63  
            impl_->cs_ +
380  
                impl_->offset(id_path),
64  
                impl_->offset(id_path),
381  
            impl_->len(id_path),
65  
            impl_->len(id_path),
382  
            impl_->decoded_[id_path]);
66  
            impl_->decoded_[id_path]);
383  
    return make_pct_string_view_unsafe(
67  
    return make_pct_string_view_unsafe(
384  
        data_, size_, dn_);
68  
        data_, size_, dn_);
385  
}
69  
}
386  

70  

387  
std::size_t
71  
std::size_t
388  
path_ref::
72  
path_ref::
389  
size() const noexcept
73  
size() const noexcept
390  
{
74  
{
391  
    if(impl_)
75  
    if(impl_)
392  
        return impl_->len(id_path);
76  
        return impl_->len(id_path);
393  
    return size_;
77  
    return size_;
394  
}
78  
}
395  

79  

396  
char const*
80  
char const*
397  
path_ref::
81  
path_ref::
398  
data() const noexcept
82  
data() const noexcept
399  
{
83  
{
400  
    if(impl_)
84  
    if(impl_)
401  
        return impl_->cs_ +
85  
        return impl_->cs_ +
402  
            impl_->offset(id_path);
86  
            impl_->offset(id_path);
403  
    return data_;
87  
    return data_;
404  
}
88  
}
405  

89  

406  
char const*
90  
char const*
407  
path_ref::
91  
path_ref::
408  
end() const noexcept
92  
end() const noexcept
409  
{
93  
{
410  
    if(impl_)
94  
    if(impl_)
411  
        return impl_->cs_ +
95  
        return impl_->cs_ +
412  
            impl_->offset(id_query);
96  
            impl_->offset(id_query);
413  
    return data_ + size_;
97  
    return data_ + size_;
414  
}
98  
}
415  

99  

416  
std::size_t
100  
std::size_t
417  
path_ref::
101  
path_ref::
418  
nseg() const noexcept
102  
nseg() const noexcept
419  
{
103  
{
420  
    if(impl_)
104  
    if(impl_)
421  
        return impl_->nseg_;
105  
        return impl_->nseg_;
422  
    return nseg_;
106  
    return nseg_;
423  
}
107  
}
424  

108  

425  
std::size_t
109  
std::size_t
426  
path_ref::
110  
path_ref::
427  
decoded_size() const noexcept
111  
decoded_size() const noexcept
428  
{
112  
{
429  
    if(impl_)
113  
    if(impl_)
430  
        return impl_->decoded_[id_path];
114  
        return impl_->decoded_[id_path];
431  
    return dn_;
115  
    return dn_;
432  
}
116  
}
433  

117  

434  
//------------------------------------------------
118  
//------------------------------------------------
435  
//
119  
//
436  
// query_ref
120  
// query_ref
437  
//
121  
//
438  
//------------------------------------------------
122  
//------------------------------------------------
439  

123  

440  
query_ref::
124  
query_ref::
441  
query_ref(
125  
query_ref(
442  
    core::string_view s,
126  
    core::string_view s,
443  
    std::size_t dn,
127  
    std::size_t dn,
444  
    std::size_t nparam) noexcept
128  
    std::size_t nparam) noexcept
445  
    : data_(s.data())
129  
    : data_(s.data())
446  
    , size_(s.size())
130  
    , size_(s.size())
447  
    , nparam_(nparam)
131  
    , nparam_(nparam)
448  
    , dn_(dn)
132  
    , dn_(dn)
449  
{
133  
{
450  
}
134  
}
451  

135  

452  
query_ref::
136  
query_ref::
453  
query_ref(
137  
query_ref(
454  
    url_impl const& impl) noexcept
138  
    url_impl const& impl) noexcept
455  
{
139  
{
456  
    if(impl.from_ == url_impl::from::url)
140  
    if(impl.from_ == url_impl::from::url)
457  
    {
141  
    {
458  
        impl_ = &impl;
142  
        impl_ = &impl;
459  
    }
143  
    }
460  
    else
144  
    else
461  
    {
145  
    {
462  
        core::string_view s = impl.get(id_query);
146  
        core::string_view s = impl.get(id_query);
463  
        if (!s.empty())
147  
        if (!s.empty())
464  
        {
148  
        {
465  
            s.remove_prefix(1);
149  
            s.remove_prefix(1);
466  
            question_mark_ = true;
150  
            question_mark_ = true;
467  
        }
151  
        }
468  
        data_ = s.data();
152  
        data_ = s.data();
469  
        size_ = s.size();
153  
        size_ = s.size();
470  
        nparam_ = impl.nparam_;
154  
        nparam_ = impl.nparam_;
471  
        dn_ = impl.decoded_[id_query];
155  
        dn_ = impl.decoded_[id_query];
472  
    }
156  
    }
473  
}
157  
}
474  

158  

475  
pct_string_view
159  
pct_string_view
476  
query_ref::
160  
query_ref::
477  
buffer() const noexcept
161  
buffer() const noexcept
478  
{
162  
{
479  
    if(impl_)
163  
    if(impl_)
480  
    {
164  
    {
481  
        auto pos = impl_->offset_[id_query];
165  
        auto pos = impl_->offset_[id_query];
482  
        auto pos1 = impl_->offset_[id_frag];
166  
        auto pos1 = impl_->offset_[id_frag];
483  
        if(pos < pos1)
167  
        if(pos < pos1)
484  
        {
168  
        {
485  
            ++pos; // no '?'
169  
            ++pos; // no '?'
486  
            return make_pct_string_view_unsafe(
170  
            return make_pct_string_view_unsafe(
487  
                impl_->cs_ + pos,
171  
                impl_->cs_ + pos,
488  
                pos1 - pos,
172  
                pos1 - pos,
489  
                impl_->decoded_[id_query]);
173  
                impl_->decoded_[id_query]);
490  
        }
174  
        }
491  
        // empty
175  
        // empty
492  
        return make_pct_string_view_unsafe(
176  
        return make_pct_string_view_unsafe(
493  
            impl_->cs_ + pos,
177  
            impl_->cs_ + pos,
494  
            0,
178  
            0,
495  
            0);
179  
            0);
496  
    }
180  
    }
497  
    // no '?'
181  
    // no '?'
498  
    return make_pct_string_view_unsafe(
182  
    return make_pct_string_view_unsafe(
499  
        data_, size_, dn_);
183  
        data_, size_, dn_);
500  
}
184  
}
501  

185  

502  
// with '?'
186  
// with '?'
503  
std::size_t
187  
std::size_t
504  
query_ref::
188  
query_ref::
505  
size() const noexcept
189  
size() const noexcept
506  
{
190  
{
507  
    if(impl_)
191  
    if(impl_)
508  
        return impl_->len(id_query);
192  
        return impl_->len(id_query);
509  
    if(size_ > 0)
193  
    if(size_ > 0)
510  
        return size_ + 1;
194  
        return size_ + 1;
511  
    return question_mark_;
195  
    return question_mark_;
512  
}
196  
}
513  

197  

514  
// no '?'
198  
// no '?'
515  
char const*
199  
char const*
516  
query_ref::
200  
query_ref::
517  
begin() const noexcept
201  
begin() const noexcept
518  
{
202  
{
519  
    if(impl_)
203  
    if(impl_)
520  
    {
204  
    {
521  
        // using the offset array here
205  
        // using the offset array here
522  
        auto pos = impl_->offset_[id_query];
206  
        auto pos = impl_->offset_[id_query];
523  
        auto pos1 = impl_->offset_[id_frag];
207  
        auto pos1 = impl_->offset_[id_frag];
524  
        if(pos < pos1)
208  
        if(pos < pos1)
525  
            return impl_->cs_ + pos + 1; // no '?'
209  
            return impl_->cs_ + pos + 1; // no '?'
526  
        // empty
210  
        // empty
527  
        return impl_->cs_ + pos;
211  
        return impl_->cs_ + pos;
528  
    }
212  
    }
529 -

 
530  
    return data_;
213  
    return data_;
531  
}
214  
}
532  

215  

533  
char const*
216  
char const*
534  
query_ref::
217  
query_ref::
535  
end() const noexcept
218  
end() const noexcept
536  
{
219  
{
537  
    if(impl_)
220  
    if(impl_)
538  
        return impl_->cs_ +
221  
        return impl_->cs_ +
539  
            impl_->offset(id_frag);
222  
            impl_->offset(id_frag);
540  
    return data_ + size_;
223  
    return data_ + size_;
541  
}
224  
}
542  

225  

543  
std::size_t
226  
std::size_t
544  
query_ref::
227  
query_ref::
545  
nparam() const noexcept
228  
nparam() const noexcept
546  
{
229  
{
547  
    if(impl_)
230  
    if(impl_)
548  
        return impl_->nparam_;
231  
        return impl_->nparam_;
549  
    return nparam_;
232  
    return nparam_;
550 -

 
551 -
#if defined(__GNUC__) && ! defined(__clang__) && defined(__MINGW32__)
 
552 -
#pragma GCC diagnostic pop
 
553 -
#endif
 
554  
}
233  
}
555  

234  

556  
} // detail
235  
} // detail
557  
} // urls
236  
} // urls
558  
} // boost
237  
} // boost