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

9  

10  

10  

11  
#include <boost/url/detail/config.hpp>
11  
#include <boost/url/detail/config.hpp>
12  
#include "relative_part_rule.hpp"
12  
#include "relative_part_rule.hpp"
13  
#include "boost/url/rfc/detail/path_rules.hpp"
13  
#include "boost/url/rfc/detail/path_rules.hpp"
14  
#include <boost/url/grammar/parse.hpp>
14  
#include <boost/url/grammar/parse.hpp>
15  

15  

16  
namespace boost {
16  
namespace boost {
17  
namespace urls {
17  
namespace urls {
18  
namespace detail {
18  
namespace detail {
19  

19  

20  
constexpr auto pchars_nc = pchars - ':';
20  
constexpr auto pchars_nc = pchars - ':';
21  

21  

22  
auto
22  
auto
23  
relative_part_rule_t::
23  
relative_part_rule_t::
24  
parse(
24  
parse(
25  
    char const*& it,
25  
    char const*& it,
26  
    char const* const end
26  
    char const* const end
27  
        ) const noexcept ->
27  
        ) const noexcept ->
28  
    system::result<value_type>
28  
    system::result<value_type>
29  
{
29  
{
30  
    value_type t;
30  
    value_type t;
31  
    if(it == end)
31  
    if(it == end)
32  
    {
32  
    {
33  
        // path-empty
33  
        // path-empty
34  
        return t;
34  
        return t;
35  
    }
35  
    }
36  
    if(end - it == 1)
36  
    if(end - it == 1)
37  
    {
37  
    {
38  
        if(*it == '/')
38  
        if(*it == '/')
39  
        {
39  
        {
40  
            // path-absolute
40  
            // path-absolute
41  
            t.path = make_pct_string_view_unsafe(
41  
            t.path = make_pct_string_view_unsafe(
42  
                it, 1, 1);
42  
                it, 1, 1);
43  
            t.segment_count = 1;
43  
            t.segment_count = 1;
44  
            ++it;
44  
            ++it;
45  
            return t;
45  
            return t;
46  
        }
46  
        }
47  
        if(*it != ':')
47  
        if(*it != ':')
48  
        {
48  
        {
49  
            // path-noscheme or
49  
            // path-noscheme or
50  
            // path-empty
50  
            // path-empty
51  
            auto rv = grammar::parse(
51  
            auto rv = grammar::parse(
52  
                it, end, segment_rule);
52  
                it, end, segment_rule);
53  
            if(! rv)
53  
            if(! rv)
54  
                return rv.error();
54  
                return rv.error();
55  
            if(! rv->empty())
55  
            if(! rv->empty())
56  
            {
56  
            {
57  
                t.path = *rv;
57  
                t.path = *rv;
58  
                t.segment_count = 1;
58  
                t.segment_count = 1;
59  
            }
59  
            }
60  
        }
60  
        }
61  
        // path-empty
61  
        // path-empty
62  
        return t;
62  
        return t;
63  
    }
63  
    }
64  
    if( it[0] == '/' &&
64  
    if( it[0] == '/' &&
65  
        it[1] == '/')
65  
        it[1] == '/')
66  
    {
66  
    {
67  
        // "//" authority
67  
        // "//" authority
68  
        it += 2;
68  
        it += 2;
69  
        auto rv = grammar::parse(
69  
        auto rv = grammar::parse(
70  
            it, end, authority_rule);
70  
            it, end, authority_rule);
71  
        if(! rv)
71  
        if(! rv)
72  
            return rv.error();
72  
            return rv.error();
73  
        t.authority = *rv;
73  
        t.authority = *rv;
74  
        t.has_authority = true;
74  
        t.has_authority = true;
75  
    }
75  
    }
76  
    if(it == end)
76  
    if(it == end)
77  
    {
77  
    {
78  
        // path-empty
78  
        // path-empty
79  
        return t;
79  
        return t;
80  
    }
80  
    }
81  
    auto const it0 = it;
81  
    auto const it0 = it;
82  
    std::size_t dn = 0;
82  
    std::size_t dn = 0;
83  
    if(*it != '/')
83  
    if(*it != '/')
84  
    {
84  
    {
85  
        // segment_nc
85  
        // segment_nc
86  
        auto rv = grammar::parse(it, end,
86  
        auto rv = grammar::parse(it, end,
87  
            pct_encoded_rule(pchars_nc));
87  
            pct_encoded_rule(pchars_nc));
88  
        if(! rv)
88  
        if(! rv)
89  
            return rv.error();
89  
            return rv.error();
90  
        if(rv->empty())
90  
        if(rv->empty())
91  
            return t;
91  
            return t;
92  
        dn += rv->decoded_size();
92  
        dn += rv->decoded_size();
93  
        ++t.segment_count;
93  
        ++t.segment_count;
94  
        if( it != end &&
94  
        if( it != end &&
95  
            *it == ':')
95  
            *it == ':')
96  
        {
96  
        {
97  
            BOOST_URL_RETURN_EC(
97  
            BOOST_URL_RETURN_EC(
98  
                grammar::error::mismatch);
98  
                grammar::error::mismatch);
99  
        }
99  
        }
100  
    }
100  
    }
101  
    while(it != end)
101  
    while(it != end)
102  
    {
102  
    {
103  
        if(*it == '/')
103  
        if(*it == '/')
104  
        {
104  
        {
105  
            ++dn;
105  
            ++dn;
106  
            ++it;
106  
            ++it;
107  
            ++t.segment_count;
107  
            ++t.segment_count;
108  
            continue;
108  
            continue;
109  
        }
109  
        }
110  
        auto rv = grammar::parse(
110  
        auto rv = grammar::parse(
111  
            it, end, segment_rule);
111  
            it, end, segment_rule);
112  
        if(! rv)
112  
        if(! rv)
113  
            return rv.error();
113  
            return rv.error();
114  
        if(rv->empty())
114  
        if(rv->empty())
115  
            break;
115  
            break;
116  
        dn += rv->decoded_size();
116  
        dn += rv->decoded_size();
117  
    }
117  
    }
118  
    t.path = make_pct_string_view_unsafe(
118  
    t.path = make_pct_string_view_unsafe(
119  
        it0, it - it0, dn);
119  
        it0, it - it0, dn);
120  
    return t;
120  
    return t;
121  
}
121  
}
122  

122  

123  
} // detail
123  
} // detail
124  
} // urls
124  
} // urls
125  
} // boost
125  
} // boost
126  

126