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/ipv6_address.hpp>
12  
#include <boost/url/ipv6_address.hpp>
13  
#include <boost/url/ipv4_address.hpp>
13  
#include <boost/url/ipv4_address.hpp>
14  
#include <boost/url/rfc/ipv6_address_rule.hpp>
14  
#include <boost/url/rfc/ipv6_address_rule.hpp>
15  
#include <boost/url/detail/except.hpp>
15  
#include <boost/url/detail/except.hpp>
16  
#include <boost/url/grammar/parse.hpp>
16  
#include <boost/url/grammar/parse.hpp>
17  
#include <cstring>
17  
#include <cstring>
18  

18  

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

21  

22  
ipv6_address::
22  
ipv6_address::
23  
ipv6_address(
23  
ipv6_address(
24  
    ipv4_address const& addr) noexcept
24  
    ipv4_address const& addr) noexcept
25  
{
25  
{
26  
    auto const v = addr.to_bytes();
26  
    auto const v = addr.to_bytes();
27  
    ipv6_address::bytes_type bytes = {
27  
    ipv6_address::bytes_type bytes = {
28  
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
28  
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
29  
      0xff, 0xff, v[0], v[1], v[2], v[3] } };
29  
      0xff, 0xff, v[0], v[1], v[2], v[3] } };
30  
    std::memcpy(&addr_, bytes.data(), 16);
30  
    std::memcpy(&addr_, bytes.data(), 16);
31  
}
31  
}
32  

32  

33  
ipv6_address::
33  
ipv6_address::
34  
ipv6_address(
34  
ipv6_address(
35  
    core::string_view s)
35  
    core::string_view s)
36  
    : ipv6_address(
36  
    : ipv6_address(
37  
        parse_ipv6_address(s
37  
        parse_ipv6_address(s
38  
            ).value(BOOST_URL_POS))
38  
            ).value(BOOST_URL_POS))
39  
{
39  
{
40  
}
40  
}
41  

41  

42  
core::string_view
42  
core::string_view
43  
ipv6_address::
43  
ipv6_address::
44  
to_buffer(
44  
to_buffer(
45  
    char* dest,
45  
    char* dest,
46  
    std::size_t dest_size) const
46  
    std::size_t dest_size) const
47  
{
47  
{
48  
    if(dest_size < max_str_len)
48  
    if(dest_size < max_str_len)
49  
        detail::throw_length_error();
49  
        detail::throw_length_error();
50  
    auto n = print_impl(dest);
50  
    auto n = print_impl(dest);
51  
    return core::string_view(dest, n);
51  
    return core::string_view(dest, n);
52  
}
52  
}
53  

53  

54  
bool
54  
bool
55  
ipv6_address::
55  
ipv6_address::
56  
is_loopback() const noexcept
56  
is_loopback() const noexcept
57  
{
57  
{
58  
    return *this == loopback();
58  
    return *this == loopback();
59  
}
59  
}
60  

60  

61  
bool
61  
bool
62  
ipv6_address::
62  
ipv6_address::
63  
is_unspecified() const noexcept
63  
is_unspecified() const noexcept
64  
{
64  
{
65  
    return *this == ipv6_address();
65  
    return *this == ipv6_address();
66  
}
66  
}
67  

67  

68  
bool
68  
bool
69  
ipv6_address::
69  
ipv6_address::
70  
is_v4_mapped() const noexcept
70  
is_v4_mapped() const noexcept
71  
{
71  
{
72  
    return
72  
    return
73  
        addr_[ 0] == 0 && addr_[ 1] == 0 &&
73  
        addr_[ 0] == 0 && addr_[ 1] == 0 &&
74  
        addr_[ 2] == 0 && addr_[ 3] == 0 &&
74  
        addr_[ 2] == 0 && addr_[ 3] == 0 &&
75  
        addr_[ 4] == 0 && addr_[ 5] == 0 &&
75  
        addr_[ 4] == 0 && addr_[ 5] == 0 &&
76  
        addr_[ 6] == 0 && addr_[ 7] == 0 &&
76  
        addr_[ 6] == 0 && addr_[ 7] == 0 &&
77  
        addr_[ 8] == 0 && addr_[ 9] == 0 &&
77  
        addr_[ 8] == 0 && addr_[ 9] == 0 &&
78  
        addr_[10] == 0xff &&
78  
        addr_[10] == 0xff &&
79  
        addr_[11] == 0xff;
79  
        addr_[11] == 0xff;
80  
}
80  
}
81  

81  

82  
ipv6_address
82  
ipv6_address
83  
ipv6_address::
83  
ipv6_address::
84  
loopback() noexcept
84  
loopback() noexcept
85  
{
85  
{
86  
    ipv6_address a;
86  
    ipv6_address a;
87  
    a.addr_[15] = 1;
87  
    a.addr_[15] = 1;
88  
    return a;
88  
    return a;
89  
}
89  
}
90  

90  

91  
void
91  
void
92  
ipv6_address::
92  
ipv6_address::
93  
write_ostream(
93  
write_ostream(
94  
    std::ostream& os) const
94  
    std::ostream& os) const
95  
{
95  
{
96  
    char buf[ipv6_address::max_str_len];
96  
    char buf[ipv6_address::max_str_len];
97  
    auto const s = to_buffer(buf, sizeof(buf));
97  
    auto const s = to_buffer(buf, sizeof(buf));
98  
    os << s;
98  
    os << s;
99  
}
99  
}
100  

100  

101  
std::size_t
101  
std::size_t
102  
ipv6_address::
102  
ipv6_address::
103  
print_impl(
103  
print_impl(
104  
    char* dest) const noexcept
104  
    char* dest) const noexcept
105  
{
105  
{
106  
    auto const count_zeroes =
106  
    auto const count_zeroes =
107  
    []( unsigned char const* first,
107  
    []( unsigned char const* first,
108  
        unsigned char const* const last)
108  
        unsigned char const* const last)
109  
    {
109  
    {
110  
        std::size_t n = 0;
110  
        std::size_t n = 0;
111  
        while(first != last)
111  
        while(first != last)
112  
        {
112  
        {
113  
            if( first[0] != 0 ||
113  
            if( first[0] != 0 ||
114  
                first[1] != 0)
114  
                first[1] != 0)
115  
                break;
115  
                break;
116  
            n += 2;
116  
            n += 2;
117  
            first += 2;
117  
            first += 2;
118  
        }
118  
        }
119  
        return n;
119  
        return n;
120  
    };
120  
    };
121  
    auto const print_hex =
121  
    auto const print_hex =
122  
    []( char* dest,
122  
    []( char* dest,
123  
        unsigned short v)
123  
        unsigned short v)
124  
    {
124  
    {
125  
        char const* const dig =
125  
        char const* const dig =
126  
            "0123456789abcdef";
126  
            "0123456789abcdef";
127  
        if(v >= 0x1000)
127  
        if(v >= 0x1000)
128  
        {
128  
        {
129  
            *dest++ = dig[v>>12];
129  
            *dest++ = dig[v>>12];
130  
            v &= 0x0fff;
130  
            v &= 0x0fff;
131  
            *dest++ = dig[v>>8];
131  
            *dest++ = dig[v>>8];
132  
            v &= 0x0ff;
132  
            v &= 0x0ff;
133  
            *dest++ = dig[v>>4];
133  
            *dest++ = dig[v>>4];
134  
            v &= 0x0f;
134  
            v &= 0x0f;
135  
            *dest++ = dig[v];
135  
            *dest++ = dig[v];
136  
        }
136  
        }
137  
        else if(v >= 0x100)
137  
        else if(v >= 0x100)
138  
        {
138  
        {
139  
            *dest++ = dig[v>>8];
139  
            *dest++ = dig[v>>8];
140  
            v &= 0x0ff;
140  
            v &= 0x0ff;
141  
            *dest++ = dig[v>>4];
141  
            *dest++ = dig[v>>4];
142  
            v &= 0x0f;
142  
            v &= 0x0f;
143  
            *dest++ = dig[v];
143  
            *dest++ = dig[v];
144  
        }
144  
        }
145  
        else if(v >= 0x10)
145  
        else if(v >= 0x10)
146  
        {
146  
        {
147  
            *dest++ = dig[v>>4];
147  
            *dest++ = dig[v>>4];
148  
            v &= 0x0f;
148  
            v &= 0x0f;
149  
            *dest++ = dig[v];
149  
            *dest++ = dig[v];
150  
        }
150  
        }
151  
        else
151  
        else
152  
        {
152  
        {
153  
            *dest++ = dig[v];
153  
            *dest++ = dig[v];
154  
        }
154  
        }
155  
        return dest;
155  
        return dest;
156  
    };
156  
    };
157  
    auto const dest0 = dest;
157  
    auto const dest0 = dest;
158  
    // find longest run of zeroes
158  
    // find longest run of zeroes
159  
    std::size_t best_len = 0;
159  
    std::size_t best_len = 0;
160  
    int best_pos = -1;
160  
    int best_pos = -1;
161  
    auto it = addr_.data();
161  
    auto it = addr_.data();
162  
    auto const v4 =
162  
    auto const v4 =
163  
        is_v4_mapped();
163  
        is_v4_mapped();
164  
    auto const end = v4 ?
164  
    auto const end = v4 ?
165  
        (it + addr_.size() - 4)
165  
        (it + addr_.size() - 4)
166  
        : it + addr_.size();
166  
        : it + addr_.size();
167  
    while(it != end)
167  
    while(it != end)
168  
    {
168  
    {
169  
        auto n = count_zeroes(
169  
        auto n = count_zeroes(
170  
            it, end);
170  
            it, end);
171  
        if(n == 0)
171  
        if(n == 0)
172  
        {
172  
        {
173  
            it += 2;
173  
            it += 2;
174  
            continue;
174  
            continue;
175  
        }
175  
        }
176  
        if(n > best_len)
176  
        if(n > best_len)
177  
        {
177  
        {
178  
            best_pos = static_cast<
178  
            best_pos = static_cast<
179  
                int>(it - addr_.data());
179  
                int>(it - addr_.data());
180  
            best_len = n;
180  
            best_len = n;
181  
        }
181  
        }
182  
        it += n;
182  
        it += n;
183  
    }
183  
    }
184  
    it = addr_.data();
184  
    it = addr_.data();
185  
    if(best_pos != 0)
185  
    if(best_pos != 0)
186  
    {
186  
    {
187  
        unsigned short v =
187  
        unsigned short v =
188  
            (it[0] * 256U) + it[1];
188  
            (it[0] * 256U) + it[1];
189  
        dest = print_hex(dest, v);
189  
        dest = print_hex(dest, v);
190  
        it += 2;
190  
        it += 2;
191  
    }
191  
    }
192  
    else
192  
    else
193  
    {
193  
    {
194  
        *dest++ = ':';
194  
        *dest++ = ':';
195  
        it += best_len;
195  
        it += best_len;
196  
        if(it == end)
196  
        if(it == end)
197  
            *dest++ = ':';
197  
            *dest++ = ':';
198  
    }
198  
    }
199  
    while(it != end)
199  
    while(it != end)
200  
    {
200  
    {
201  
        *dest++ = ':';
201  
        *dest++ = ':';
202  
        if(it - addr_.data() ==
202  
        if(it - addr_.data() ==
203  
            best_pos)
203  
            best_pos)
204  
        {
204  
        {
205  
            it += best_len;
205  
            it += best_len;
206  
            if(it == end)
206  
            if(it == end)
207  
                *dest++ = ':';
207  
                *dest++ = ':';
208  
            continue;
208  
            continue;
209  
        }
209  
        }
210  
        unsigned short v =
210  
        unsigned short v =
211  
            (it[0] * 256U) + it[1];
211  
            (it[0] * 256U) + it[1];
212  
        dest = print_hex(dest, v);
212  
        dest = print_hex(dest, v);
213  
        it += 2;
213  
        it += 2;
214  
    }
214  
    }
215  
    if(v4)
215  
    if(v4)
216  
    {
216  
    {
217  
        ipv4_address::bytes_type bytes;
217  
        ipv4_address::bytes_type bytes;
218  
        bytes[0] = it[0];
218  
        bytes[0] = it[0];
219  
        bytes[1] = it[1];
219  
        bytes[1] = it[1];
220  
        bytes[2] = it[2];
220  
        bytes[2] = it[2];
221  
        bytes[3] = it[3];
221  
        bytes[3] = it[3];
222  
        ipv4_address a(bytes);
222  
        ipv4_address a(bytes);
223  
        *dest++ = ':';
223  
        *dest++ = ':';
224  
        dest += a.print_impl(dest);
224  
        dest += a.print_impl(dest);
225  
    }
225  
    }
226  
    return dest - dest0;
226  
    return dest - dest0;
227  
}
227  
}
228  

228  

229  
void
229  
void
230  
ipv6_address::
230  
ipv6_address::
231  
to_string_impl(
231  
to_string_impl(
232  
    string_token::arg& t) const
232  
    string_token::arg& t) const
233  
{
233  
{
234  
    char buf[max_str_len];
234  
    char buf[max_str_len];
235  
    auto const n = print_impl(buf);
235  
    auto const n = print_impl(buf);
236  
    char* dest = t.prepare(n);
236  
    char* dest = t.prepare(n);
237  
    std::memcpy(dest, buf, n);
237  
    std::memcpy(dest, buf, n);
238  
}
238  
}
239  

239  

240  
//------------------------------------------------
240  
//------------------------------------------------
241  

241  

242  
auto
242  
auto
243  
parse_ipv6_address(
243  
parse_ipv6_address(
244  
    core::string_view s) noexcept ->
244  
    core::string_view s) noexcept ->
245  
        system::result<ipv6_address>
245  
        system::result<ipv6_address>
246  
{
246  
{
247  
    return grammar::parse(
247  
    return grammar::parse(
248  
        s, ipv6_address_rule);
248  
        s, ipv6_address_rule);
249  
}
249  
}
250  

250  

251  
} // urls
251  
} // urls
252  
} // boost
252  
} // boost
253  

253