1  
//
1  
//
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.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 <boost/url/rfc/ipv6_address_rule.hpp>
12  
#include <boost/url/rfc/ipv6_address_rule.hpp>
13  
#include <boost/url/rfc/ipv4_address_rule.hpp>
13  
#include <boost/url/rfc/ipv4_address_rule.hpp>
14  
#include "detail/h16_rule.hpp"
14  
#include "detail/h16_rule.hpp"
15  
#include <boost/url/grammar/charset.hpp>
15  
#include <boost/url/grammar/charset.hpp>
16  
#include <boost/url/grammar/hexdig_chars.hpp>
16  
#include <boost/url/grammar/hexdig_chars.hpp>
17  
#include <boost/url/grammar/parse.hpp>
17  
#include <boost/url/grammar/parse.hpp>
18  
#include <boost/assert.hpp>
18  
#include <boost/assert.hpp>
19  
#include <cstring>
19  
#include <cstring>
20  

20  

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

23  

24  
namespace detail {
24  
namespace detail {
25  

25  

26  
// return `true` if the hex
26  
// return `true` if the hex
27  
// word could be 0..255 if
27  
// word could be 0..255 if
28  
// interpreted as decimal
28  
// interpreted as decimal
29  
static
29  
static
30  
bool
30  
bool
31  
maybe_octet(
31  
maybe_octet(
32  
    unsigned char const* p) noexcept
32  
    unsigned char const* p) noexcept
33  
{
33  
{
34  
    unsigned short word =
34  
    unsigned short word =
35  
        static_cast<unsigned short>(
35  
        static_cast<unsigned short>(
36  
            p[0]) * 256 +
36  
            p[0]) * 256 +
37  
        static_cast<unsigned short>(
37  
        static_cast<unsigned short>(
38  
            p[1]);
38  
            p[1]);
39  
    if(word > 0x255)
39  
    if(word > 0x255)
40  
        return false;
40  
        return false;
41  
    if(((word >>  4) & 0xf) > 9)
41  
    if(((word >>  4) & 0xf) > 9)
42  
        return false;
42  
        return false;
43  
    if((word & 0xf) > 9)
43  
    if((word & 0xf) > 9)
44  
        return false;
44  
        return false;
45  
    return true;
45  
    return true;
46  
}
46  
}
47  

47  

48  
} // detail
48  
} // detail
49  

49  

50  
auto
50  
auto
51  
implementation_defined::ipv6_address_rule_t::
51  
implementation_defined::ipv6_address_rule_t::
52  
parse(
52  
parse(
53  
    char const*& it,
53  
    char const*& it,
54  
    char const* const end
54  
    char const* const end
55  
        ) const noexcept ->
55  
        ) const noexcept ->
56  
    system::result<ipv6_address>
56  
    system::result<ipv6_address>
57  
{
57  
{
58  
    int n = 8;      // words needed
58  
    int n = 8;      // words needed
59  
    int b = -1;     // value of n
59  
    int b = -1;     // value of n
60  
                    // when '::' seen
60  
                    // when '::' seen
61  
    bool c = false; // need colon
61  
    bool c = false; // need colon
62  
    auto prev = it;
62  
    auto prev = it;
63  
    ipv6_address::bytes_type bytes;
63  
    ipv6_address::bytes_type bytes;
64  
    system::result<detail::h16_rule_t::value_type> rv;
64  
    system::result<detail::h16_rule_t::value_type> rv;
65  
    for(;;)
65  
    for(;;)
66  
    {
66  
    {
67  
        if(it == end)
67  
        if(it == end)
68  
        {
68  
        {
69  
            if(b != -1)
69  
            if(b != -1)
70  
            {
70  
            {
71  
                // end in "::"
71  
                // end in "::"
72  
                break;
72  
                break;
73  
            }
73  
            }
74  
            BOOST_ASSERT(n > 0);
74  
            BOOST_ASSERT(n > 0);
75  
            // not enough words
75  
            // not enough words
76  
            BOOST_URL_RETURN_EC(
76  
            BOOST_URL_RETURN_EC(
77  
                grammar::error::invalid);
77  
                grammar::error::invalid);
78  
        }
78  
        }
79  
        if(*it == ':')
79  
        if(*it == ':')
80  
        {
80  
        {
81  
            ++it;
81  
            ++it;
82  
            if(it == end)
82  
            if(it == end)
83  
            {
83  
            {
84  
                // expected ':'
84  
                // expected ':'
85  
                BOOST_URL_RETURN_EC(
85  
                BOOST_URL_RETURN_EC(
86  
                    grammar::error::invalid);
86  
                    grammar::error::invalid);
87  
            }
87  
            }
88  
            if(*it == ':')
88  
            if(*it == ':')
89  
            {
89  
            {
90  
                if(b == -1)
90  
                if(b == -1)
91  
                {
91  
                {
92  
                    // first "::"
92  
                    // first "::"
93  
                    ++it;
93  
                    ++it;
94  
                    --n;
94  
                    --n;
95  
                    b = n;
95  
                    b = n;
96  
                    if(n == 0)
96  
                    if(n == 0)
97  
                        break;
97  
                        break;
98  
                    c = false;
98  
                    c = false;
99  
                    continue;
99  
                    continue;
100  
                }
100  
                }
101  
                // extra "::" found
101  
                // extra "::" found
102  
                BOOST_URL_RETURN_EC(
102  
                BOOST_URL_RETURN_EC(
103  
                    grammar::error::invalid);
103  
                    grammar::error::invalid);
104  
            }
104  
            }
105  
            if(c)
105  
            if(c)
106  
            {
106  
            {
107  
                prev = it;
107  
                prev = it;
108  
                rv = grammar::parse(
108  
                rv = grammar::parse(
109  
                    it, end,
109  
                    it, end,
110  
                    detail::h16_rule);
110  
                    detail::h16_rule);
111  
                if(! rv)
111  
                if(! rv)
112  
                    return rv.error();
112  
                    return rv.error();
113  
                bytes[2*(8-n)+0] = rv->hi;
113  
                bytes[2*(8-n)+0] = rv->hi;
114  
                bytes[2*(8-n)+1] = rv->lo;
114  
                bytes[2*(8-n)+1] = rv->lo;
115  
                --n;
115  
                --n;
116  
                if(n == 0)
116  
                if(n == 0)
117  
                    break;
117  
                    break;
118  
                continue;
118  
                continue;
119  
            }
119  
            }
120  
            // expected h16
120  
            // expected h16
121  
            BOOST_URL_RETURN_EC(
121  
            BOOST_URL_RETURN_EC(
122  
                grammar::error::invalid);
122  
                grammar::error::invalid);
123  
        }
123  
        }
124  
        if(*it == '.')
124  
        if(*it == '.')
125  
        {
125  
        {
126  
            if(b == -1 && n > 1)
126  
            if(b == -1 && n > 1)
127  
            {
127  
            {
128  
                // not enough h16
128  
                // not enough h16
129  
                BOOST_URL_RETURN_EC(
129  
                BOOST_URL_RETURN_EC(
130  
                    grammar::error::invalid);
130  
                    grammar::error::invalid);
131  
            }
131  
            }
132  
            if(! detail::maybe_octet(
132  
            if(! detail::maybe_octet(
133  
                &bytes[2*(7-n)]))
133  
                &bytes[2*(7-n)]))
134  
            {
134  
            {
135  
                // invalid octet
135  
                // invalid octet
136  
                BOOST_URL_RETURN_EC(
136  
                BOOST_URL_RETURN_EC(
137  
                    grammar::error::invalid);
137  
                    grammar::error::invalid);
138  
            }
138  
            }
139  
            // rewind the h16 and
139  
            // rewind the h16 and
140  
            // parse it as ipv4
140  
            // parse it as ipv4
141  
            it = prev;
141  
            it = prev;
142  
            auto rv1 = grammar::parse(
142  
            auto rv1 = grammar::parse(
143  
                it, end, ipv4_address_rule);
143  
                it, end, ipv4_address_rule);
144  
            if(! rv1)
144  
            if(! rv1)
145  
                return rv1.error();
145  
                return rv1.error();
146  
            auto v4 = *rv1;
146  
            auto v4 = *rv1;
147  
            auto const b4 =
147  
            auto const b4 =
148  
                v4.to_bytes();
148  
                v4.to_bytes();
149  
            bytes[2*(7-n)+0] = b4[0];
149  
            bytes[2*(7-n)+0] = b4[0];
150  
            bytes[2*(7-n)+1] = b4[1];
150  
            bytes[2*(7-n)+1] = b4[1];
151  
            bytes[2*(7-n)+2] = b4[2];
151  
            bytes[2*(7-n)+2] = b4[2];
152  
            bytes[2*(7-n)+3] = b4[3];
152  
            bytes[2*(7-n)+3] = b4[3];
153  
            --n;
153  
            --n;
154  
            break;
154  
            break;
155  
        }
155  
        }
156  
        auto d =
156  
        auto d =
157  
            grammar::hexdig_value(*it);
157  
            grammar::hexdig_value(*it);
158  
        if( b != -1 &&
158  
        if( b != -1 &&
159  
            d < 0)
159  
            d < 0)
160  
        {
160  
        {
161  
            // ends in "::"
161  
            // ends in "::"
162  
            break;
162  
            break;
163  
        }
163  
        }
164  
        if(! c)
164  
        if(! c)
165  
        {
165  
        {
166  
            prev = it;
166  
            prev = it;
167  
            rv = grammar::parse(
167  
            rv = grammar::parse(
168  
                it, end,
168  
                it, end,
169  
                detail::h16_rule);
169  
                detail::h16_rule);
170  
            if(! rv)
170  
            if(! rv)
171  
                return rv.error();
171  
                return rv.error();
172  
            bytes[2*(8-n)+0] = rv->hi;
172  
            bytes[2*(8-n)+0] = rv->hi;
173  
            bytes[2*(8-n)+1] = rv->lo;
173  
            bytes[2*(8-n)+1] = rv->lo;
174  
            --n;
174  
            --n;
175  
            if(n == 0)
175  
            if(n == 0)
176  
                break;
176  
                break;
177  
            c = true;
177  
            c = true;
178  
            continue;
178  
            continue;
179  
        }
179  
        }
180  
        // ':' divides a word
180  
        // ':' divides a word
181  
        BOOST_URL_RETURN_EC(
181  
        BOOST_URL_RETURN_EC(
182  
            grammar::error::invalid);
182  
            grammar::error::invalid);
183  
    }
183  
    }
184  
    if(b == -1)
184  
    if(b == -1)
185  
        return ipv6_address{bytes};
185  
        return ipv6_address{bytes};
186  
    if(b == n)
186  
    if(b == n)
187  
    {
187  
    {
188  
        // "::" last
188  
        // "::" last
189  
        auto const i =
189  
        auto const i =
190  
            2 * (7 - n);
190  
            2 * (7 - n);
191  
        std::memset(
191  
        std::memset(
192  
            &bytes[i],
192  
            &bytes[i],
193  
            0, 16 - i);
193  
            0, 16 - i);
194  
    }
194  
    }
195  
    else if(b == 7)
195  
    else if(b == 7)
196  
    {
196  
    {
197  
        // "::" first
197  
        // "::" first
198  
        auto const i =
198  
        auto const i =
199  
            2 * (b - n);
199  
            2 * (b - n);
200  
        std::memmove(
200  
        std::memmove(
201  
            &bytes[16 - i],
201  
            &bytes[16 - i],
202  
            &bytes[2],
202  
            &bytes[2],
203  
            i);
203  
            i);
204  
        std::memset(
204  
        std::memset(
205  
            &bytes[0],
205  
            &bytes[0],
206  
            0, 16 - i);
206  
            0, 16 - i);
207  
    }
207  
    }
208  
    else
208  
    else
209  
    {
209  
    {
210  
        // "::" in middle
210  
        // "::" in middle
211  
        auto const i0 =
211  
        auto const i0 =
212  
            2 * (7 - b);
212  
            2 * (7 - b);
213  
        auto const i1 =
213  
        auto const i1 =
214  
            2 * (b - n);
214  
            2 * (b - n);
215  
        std::memmove(
215  
        std::memmove(
216  
            &bytes[16 - i1],
216  
            &bytes[16 - i1],
217  
            &bytes[i0 + 2],
217  
            &bytes[i0 + 2],
218  
            i1);
218  
            i1);
219  
        std::memset(
219  
        std::memset(
220  
            &bytes[i0],
220  
            &bytes[i0],
221  
            0, 16 - (i0 + i1));
221  
            0, 16 - (i0 + i1));
222  
    }
222  
    }
223  
    return ipv6_address{bytes};
223  
    return ipv6_address{bytes};
224  
}
224  
}
225  

225  

226  
} // urls
226  
} // urls
227  
} // boost
227  
} // boost
228  

228