Line | Branch | Exec | Source |
---|---|---|---|
1 | // | ||
2 | // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) | ||
3 | // | ||
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) | ||
6 | // | ||
7 | // Official repository: https://github.com/boostorg/url | ||
8 | // | ||
9 | |||
10 | |||
11 | #include <boost/url/detail/config.hpp> | ||
12 | #include <boost/url/rfc/ipv6_address_rule.hpp> | ||
13 | #include <boost/url/rfc/ipv4_address_rule.hpp> | ||
14 | #include "detail/h16_rule.hpp" | ||
15 | #include <boost/url/grammar/charset.hpp> | ||
16 | #include <boost/url/grammar/hexdig_chars.hpp> | ||
17 | #include <boost/url/grammar/parse.hpp> | ||
18 | #include <boost/assert.hpp> | ||
19 | #include <cstring> | ||
20 | |||
21 | namespace boost { | ||
22 | namespace urls { | ||
23 | |||
24 | namespace detail { | ||
25 | |||
26 | // return `true` if the hex | ||
27 | // word could be 0..255 if | ||
28 | // interpreted as decimal | ||
29 | static | ||
30 | bool | ||
31 | 65 | maybe_octet( | |
32 | unsigned char const* p) noexcept | ||
33 | { | ||
34 | 65 | unsigned short word = | |
35 | static_cast<unsigned short>( | ||
36 | 65 | p[0]) * 256 + | |
37 | static_cast<unsigned short>( | ||
38 | 65 | p[1]); | |
39 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 58 times.
|
65 | if(word > 0x255) |
40 | 7 | return false; | |
41 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 57 times.
|
58 | if(((word >> 4) & 0xf) > 9) |
42 | 1 | return false; | |
43 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 55 times.
|
57 | if((word & 0xf) > 9) |
44 | 2 | return false; | |
45 | 55 | return true; | |
46 | } | ||
47 | |||
48 | } // detail | ||
49 | |||
50 | auto | ||
51 | 288 | ipv6_address_rule_t:: | |
52 | parse( | ||
53 | char const*& it, | ||
54 | char const* const end | ||
55 | ) const noexcept -> | ||
56 | system::result<ipv6_address> | ||
57 | { | ||
58 | 288 | int n = 8; // words needed | |
59 | 288 | int b = -1; // value of n | |
60 | // when '::' seen | ||
61 | 288 | bool c = false; // need colon | |
62 | 288 | auto prev = it; | |
63 | ipv6_address::bytes_type bytes; | ||
64 | 288 | system::result<detail::h16_rule_t::value_type> rv; | |
65 | for(;;) | ||
66 | { | ||
67 |
2/2✓ Branch 0 taken 91 times.
✓ Branch 1 taken 1233 times.
|
1324 | if(it == end) |
68 | { | ||
69 |
2/2✓ Branch 0 taken 83 times.
✓ Branch 1 taken 8 times.
|
91 | if(b != -1) |
70 | { | ||
71 | // end in "::" | ||
72 | 83 | break; | |
73 | } | ||
74 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | BOOST_ASSERT(n > 0); |
75 | // not enough words | ||
76 | 8 | BOOST_URL_RETURN_EC( | |
77 | grammar::error::invalid); | ||
78 | } | ||
79 |
2/2✓ Branch 0 taken 794 times.
✓ Branch 1 taken 439 times.
|
1233 | if(*it == ':') |
80 | { | ||
81 | 794 | ++it; | |
82 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 789 times.
|
794 | if(it == end) |
83 | { | ||
84 | // expected ':' | ||
85 | 5 | BOOST_URL_RETURN_EC( | |
86 | grammar::error::invalid); | ||
87 | } | ||
88 |
2/2✓ Branch 0 taken 186 times.
✓ Branch 1 taken 603 times.
|
789 | if(*it == ':') |
89 | { | ||
90 |
2/2✓ Branch 0 taken 183 times.
✓ Branch 1 taken 3 times.
|
186 | if(b == -1) |
91 | { | ||
92 | // first "::" | ||
93 | 183 | ++it; | |
94 | 183 | --n; | |
95 | 183 | b = n; | |
96 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 181 times.
|
183 | if(n == 0) |
97 | 2 | break; | |
98 | 181 | c = false; | |
99 | 181 | continue; | |
100 | } | ||
101 | // extra "::" found | ||
102 | 3 | BOOST_URL_RETURN_EC( | |
103 | grammar::error::invalid); | ||
104 | } | ||
105 |
2/2✓ Branch 0 taken 597 times.
✓ Branch 1 taken 6 times.
|
603 | if(c) |
106 | { | ||
107 | 597 | prev = it; | |
108 | rv = grammar::parse( | ||
109 | it, end, | ||
110 | 597 | detail::h16_rule); | |
111 |
2/2✓ Branch 1 taken 5 times.
✓ Branch 2 taken 592 times.
|
597 | if(! rv) |
112 | 5 | return rv.error(); | |
113 | 592 | bytes[2*(8-n)+0] = rv->hi; | |
114 | 592 | bytes[2*(8-n)+1] = rv->lo; | |
115 | 592 | --n; | |
116 |
2/2✓ Branch 0 taken 51 times.
✓ Branch 1 taken 541 times.
|
592 | if(n == 0) |
117 | 51 | break; | |
118 | 541 | continue; | |
119 | } | ||
120 | // expected h16 | ||
121 | 6 | BOOST_URL_RETURN_EC( | |
122 | grammar::error::invalid); | ||
123 | } | ||
124 |
2/2✓ Branch 0 taken 75 times.
✓ Branch 1 taken 364 times.
|
439 | if(*it == '.') |
125 | { | ||
126 |
4/4✓ Branch 0 taken 15 times.
✓ Branch 1 taken 60 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 5 times.
|
75 | if(b == -1 && n > 1) |
127 | { | ||
128 | // not enough h16 | ||
129 | 10 | BOOST_URL_RETURN_EC( | |
130 | grammar::error::invalid); | ||
131 | } | ||
132 |
2/2✓ Branch 1 taken 10 times.
✓ Branch 2 taken 55 times.
|
65 | if(! detail::maybe_octet( |
133 | 65 | &bytes[2*(7-n)])) | |
134 | { | ||
135 | // invalid octet | ||
136 | 10 | BOOST_URL_RETURN_EC( | |
137 | grammar::error::invalid); | ||
138 | } | ||
139 | // rewind the h16 and | ||
140 | // parse it as ipv4 | ||
141 | 55 | it = prev; | |
142 | auto rv1 = grammar::parse( | ||
143 | 55 | it, end, ipv4_address_rule); | |
144 |
2/2✓ Branch 1 taken 22 times.
✓ Branch 2 taken 33 times.
|
55 | if(! rv1) |
145 | 22 | return rv1.error(); | |
146 | 33 | auto v4 = *rv1; | |
147 | auto const b4 = | ||
148 | 33 | v4.to_bytes(); | |
149 | 33 | bytes[2*(7-n)+0] = b4[0]; | |
150 | 33 | bytes[2*(7-n)+1] = b4[1]; | |
151 | 33 | bytes[2*(7-n)+2] = b4[2]; | |
152 | 33 | bytes[2*(7-n)+3] = b4[3]; | |
153 | 33 | --n; | |
154 | 33 | break; | |
155 | } | ||
156 | auto d = | ||
157 | 364 | grammar::hexdig_value(*it); | |
158 |
4/4✓ Branch 0 taken 170 times.
✓ Branch 1 taken 194 times.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 145 times.
|
364 | if( b != -1 && |
159 | d < 0) | ||
160 | { | ||
161 | // ends in "::" | ||
162 | 25 | break; | |
163 | } | ||
164 |
2/2✓ Branch 0 taken 335 times.
✓ Branch 1 taken 4 times.
|
339 | if(! c) |
165 | { | ||
166 | 335 | prev = it; | |
167 | rv = grammar::parse( | ||
168 | it, end, | ||
169 | 335 | detail::h16_rule); | |
170 |
2/2✓ Branch 1 taken 20 times.
✓ Branch 2 taken 315 times.
|
335 | if(! rv) |
171 | 20 | return rv.error(); | |
172 | 315 | bytes[2*(8-n)+0] = rv->hi; | |
173 | 315 | bytes[2*(8-n)+1] = rv->lo; | |
174 | 315 | --n; | |
175 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 314 times.
|
315 | if(n == 0) |
176 | 1 | break; | |
177 | 314 | c = true; | |
178 | 314 | continue; | |
179 | } | ||
180 | // ':' divides a word | ||
181 | 4 | BOOST_URL_RETURN_EC( | |
182 | grammar::error::invalid); | ||
183 | 1036 | } | |
184 |
2/2✓ Branch 0 taken 50 times.
✓ Branch 1 taken 145 times.
|
195 | if(b == -1) |
185 | 50 | return ipv6_address{bytes}; | |
186 |
2/2✓ Branch 0 taken 34 times.
✓ Branch 1 taken 111 times.
|
145 | if(b == n) |
187 | { | ||
188 | // "::" last | ||
189 | 34 | auto const i = | |
190 | 34 | 2 * (7 - n); | |
191 | 34 | std::memset( | |
192 | 34 | &bytes[i], | |
193 | 34 | 0, 16 - i); | |
194 | } | ||
195 |
2/2✓ Branch 0 taken 45 times.
✓ Branch 1 taken 66 times.
|
111 | else if(b == 7) |
196 | { | ||
197 | // "::" first | ||
198 | 45 | auto const i = | |
199 | 45 | 2 * (b - n); | |
200 | 90 | std::memmove( | |
201 | 45 | &bytes[16 - i], | |
202 | 45 | &bytes[2], | |
203 | i); | ||
204 | 45 | std::memset( | |
205 | 45 | &bytes[0], | |
206 | 45 | 0, 16 - i); | |
207 | } | ||
208 | else | ||
209 | { | ||
210 | // "::" in middle | ||
211 | 66 | auto const i0 = | |
212 | 66 | 2 * (7 - b); | |
213 | 66 | auto const i1 = | |
214 | 66 | 2 * (b - n); | |
215 | 132 | std::memmove( | |
216 | 66 | &bytes[16 - i1], | |
217 | 66 | &bytes[i0 + 2], | |
218 | i1); | ||
219 | 66 | std::memset( | |
220 | 66 | &bytes[i0], | |
221 | 66 | 0, 16 - (i0 + i1)); | |
222 | } | ||
223 | 145 | return ipv6_address{bytes}; | |
224 | } | ||
225 | |||
226 | } // urls | ||
227 | } // boost | ||
228 | |||
229 |